# views.py (Enhanced) from django.shortcuts import render, get_object_or_404 from django.http import JsonResponse from django.views import View from django.core.cache import cache import json import logging from core.models import AttributeScore, CategoryAttributeRule, Product from core.services.attribute_scorer import AttributeQualityScorer from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator logger = logging.getLogger(__name__) # @method_decorator(csrf_exempt, name='dispatch') # class AttributeScoreView(View): # """Enhanced API view with caching and better error handling""" # def __init__(self, *args, **kwargs): # super().__init__(*args, **kwargs) # self.scorer = AttributeQualityScorer(use_ai=True) # def post(self, request, *args, **kwargs): # """Score a single product with AI suggestions""" # try: # data = json.loads(request.body) # product_data = data.get('product', {}) # sku = product_data.get('sku') # use_ai = data.get('use_ai', True) # if not sku: # return JsonResponse({'error': 'SKU is required'}, status=400) # # Validate category # category = product_data.get('category', '') # if not category: # return JsonResponse({'error': 'Category is required'}, status=400) # # Get or create product # product, created = Product.objects.get_or_create( # sku=sku, # defaults={ # 'title': product_data.get('title', ''), # 'description': product_data.get('description', ''), # 'category': category, # 'attributes': product_data.get('attributes', {}) # } # ) # # Update if exists # if not created: # product.title = product_data.get('title', product.title) # product.description = product_data.get('description', product.description) # product.attributes = product_data.get('attributes', product.attributes) # product.save() # # Get category rules (with caching) # cache_key = f"category_rules_{category}" # rules = cache.get(cache_key) # if rules is None: # rules = list(CategoryAttributeRule.objects.filter(category=category).values()) # cache.set(cache_key, rules, 3600) # Cache for 1 hour # if not rules: # return JsonResponse({ # 'error': f'No rules defined for category: {category}', # 'suggestion': 'Please configure category rules first' # }, status=400) # # Score the product # score_result = self.scorer.score_product( # { # 'sku': product.sku, # 'category': product.category, # 'title': product.title, # 'description': product.description, # 'attributes': product.attributes # }, # rules, # generate_ai_suggestions=use_ai # ) # # Save score # AttributeScore.objects.create( # product=product, # score=score_result['final_score'], # max_score=score_result['max_score'], # details=score_result['breakdown'], # issues=score_result['issues'], # suggestions=score_result['suggestions'], # ai_suggestions=score_result.get('ai_suggestions', {}), # processing_time=score_result.get('processing_time', 0) # ) # return JsonResponse({ # 'success': True, # 'product_sku': sku, # 'created': created, # 'score_result': score_result # }) # except json.JSONDecodeError: # return JsonResponse({'error': 'Invalid JSON'}, status=400) # except Exception as e: # logger.error(f"Error scoring product: {str(e)}", exc_info=True) # return JsonResponse({'error': str(e)}, status=500) # def get(self, request, sku=None): # """Get latest score for a product""" # if not sku: # return JsonResponse({'error': 'SKU parameter required'}, status=400) # try: # product = get_object_or_404(Product, sku=sku) # latest_score = product.attribute_scores.order_by('-created_at').first() # if not latest_score: # return JsonResponse({ # 'message': 'No scores found for this product', # 'sku': sku # }, status=404) # return JsonResponse({ # 'sku': product.sku, # 'title': product.title, # 'category': product.category, # 'attributes': product.attributes, # 'score': latest_score.score, # 'max_score': latest_score.max_score, # 'details': latest_score.details, # 'issues': latest_score.issues, # 'suggestions': latest_score.suggestions, # 'ai_suggestions': latest_score.ai_suggestions, # 'processing_time': latest_score.processing_time, # 'scored_at': latest_score.created_at.isoformat() # }) # except Exception as e: # logger.error(f"Error retrieving score: {str(e)}") # return JsonResponse({'error': str(e)}, status=500) @method_decorator(csrf_exempt, name='dispatch') class AttributeScoreView(View): """Enhanced API view with caching and AI suggestions""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.scorer = AttributeQualityScorer(use_ai=True) # enable AI def post(self, request, *args, **kwargs): """Score a single product with AI suggestions""" try: data = json.loads(request.body) product_data = data.get('product', {}) sku = product_data.get('sku') use_ai = data.get('use_ai', True) if not sku: return JsonResponse({'error': 'SKU is required'}, status=400) category = product_data.get('category', '') if not category: return JsonResponse({'error': 'Category is required'}, status=400) # Get or create product product, created = Product.objects.get_or_create( sku=sku, defaults={ 'title': product_data.get('title', ''), 'description': product_data.get('description', ''), 'category': category, 'attributes': product_data.get('attributes', {}) } ) # Update if exists if not created: product.title = product_data.get('title', product.title) product.description = product_data.get('description', product.description) product.attributes = product_data.get('attributes', product.attributes) product.save() # Get rules (cached) cache_key = f"category_rules_{category}" rules = cache.get(cache_key) if rules is None: rules = list(CategoryAttributeRule.objects.filter(category=category).values()) cache.set(cache_key, rules, 3600) if not rules: return JsonResponse({'error': f'No rules defined for {category}'}, status=400) # Force AI suggestions score_result = self.scorer.score_product( { 'sku': product.sku, 'category': product.category, 'title': product.title, 'description': product.description, 'attributes': product.attributes }, rules, generate_ai_suggestions=True # always generate AI ) # Save score AttributeScore.objects.create( product=product, score=score_result['final_score'], max_score=score_result['max_score'], details=score_result['breakdown'], issues=score_result['issues'], suggestions=score_result['suggestions'], ai_suggestions=score_result.get('ai_suggestions', {}), processing_time=score_result.get('processing_time', 0) ) return JsonResponse({ 'success': True, 'product_sku': sku, 'created': created, 'score_result': score_result }) except json.JSONDecodeError: return JsonResponse({'error': 'Invalid JSON'}, status=400) except Exception as e: logger.error(f"Error scoring product: {str(e)}", exc_info=True) return JsonResponse({'error': str(e)}, status=500) from django.views import View from django.http import JsonResponse from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt import json import logging from .models import Product, CategoryAttributeRule, AttributeScore from .services.attribute_scorer import AttributeQualityScorer logger = logging.getLogger(__name__) # @method_decorator(csrf_exempt, name='dispatch') # class BatchScoreView(View): # """Batch scoring endpoint with AI suggestions""" # def __init__(self, *args, **kwargs): # super().__init__(*args, **kwargs) # self.scorer = AttributeQualityScorer(use_ai=True) # AI enabled # def post(self, request): # """Score multiple products""" # try: # data = json.loads(request.body) # products = data.get('products', []) # if not products: # return JsonResponse({'error': 'No products provided'}, status=400) # results = [] # errors = [] # for product_data in products[:100]: # Limit to 100 products # sku = product_data.get('sku') # category = product_data.get('category') # if not sku or not category: # errors.append({'sku': sku, 'error': 'Missing SKU or category'}) # continue # try: # # Get category rules # rules = list(CategoryAttributeRule.objects.filter(category=category).values()) # if not rules: # errors.append({'sku': sku, 'error': f'No rules defined for category {category}'}) # continue # # Score with AI suggestions enabled # score_result = self.scorer.score_product( # product_data, # rules, # generate_ai_suggestions=True # ) # # Save score in DB # product, created = Product.objects.get_or_create( # sku=sku, # defaults={ # 'title': product_data.get('title', ''), # 'description': product_data.get('description', ''), # 'category': category, # 'attributes': product_data.get('attributes', {}) # } # ) # if not created: # product.title = product_data.get('title', product.title) # product.description = product_data.get('description', product.description) # product.attributes = product_data.get('attributes', product.attributes) # product.save() # AttributeScore.objects.create( # product=product, # score=score_result['final_score'], # max_score=score_result['max_score'], # details=score_result['breakdown'], # issues=score_result['issues'], # suggestions=score_result['suggestions'], # ai_suggestions=score_result.get('ai_suggestions', {}), # processing_time=score_result.get('processing_time', 0) # ) # results.append({ # 'sku': sku, # 'final_score': score_result['final_score'], # 'max_score': score_result['max_score'], # 'breakdown': score_result['breakdown'], # 'issues': score_result['issues'], # 'suggestions': score_result['suggestions'], # 'ai_suggestions': score_result.get('ai_suggestions', {}), # 'processing_time': score_result.get('processing_time', 0) # }) # except Exception as e: # logger.error(f"Error scoring SKU {sku}: {str(e)}", exc_info=True) # errors.append({'sku': sku, 'error': str(e)}) # return JsonResponse({ # 'success': True, # 'processed': len(results), # 'results': results, # 'errors': errors # }) # except Exception as e: # logger.error(f"Batch scoring error: {str(e)}", exc_info=True) # return JsonResponse({'error': str(e)}, status=500) @method_decorator(csrf_exempt, name='dispatch') class BatchScoreView(View): """Batch scoring with AI suggestions""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.scorer = AttributeQualityScorer(use_ai=True) # enable AI even for batch def post(self, request): try: data = json.loads(request.body) products = data.get('products', []) if not products: return JsonResponse({'error': 'No products provided'}, status=400) results = [] errors = [] for product_data in products[:100]: # limit 100 try: sku = product_data.get('sku') category = product_data.get('category') if not sku or not category: errors.append({'sku': sku, 'error': 'Missing SKU or category'}) continue # Get rules rules = list(CategoryAttributeRule.objects.filter(category=category).values()) if not rules: errors.append({'sku': sku, 'error': f'No rules for category {category}'}) continue # Force AI suggestions score_result = self.scorer.score_product( product_data, rules, generate_ai_suggestions=True # <- key change ) results.append({ 'sku': sku, 'final_score': score_result['final_score'], 'max_score': score_result['max_score'], 'breakdown': score_result['breakdown'], 'issues': score_result['issues'], 'suggestions': score_result['suggestions'], 'ai_suggestions': score_result.get('ai_suggestions', {}), 'processing_time': score_result.get('processing_time', 0) }) except Exception as e: errors.append({'sku': product_data.get('sku'), 'error': str(e)}) return JsonResponse({ 'success': True, 'processed': len(results), 'results': results, 'errors': errors }) except Exception as e: logger.error(f"Batch scoring error: {str(e)}") return JsonResponse({'error': str(e)}, status=500)