""" Recommendation Engine Views für ML-basierte Empfehlungen """ from django.shortcuts import render from django.http import JsonResponse from django.contrib.auth.decorators import login_required from django.utils import timezone from django.db.models import Q, Count, Avg, Sum from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from .models import UserBehavior, UserProfile, ProductSimilarity, Recommendation, RecommendationModel, ABTest, RecommendationAnalytics from .services import RecommendationService import json @api_view(['GET']) @permission_classes([IsAuthenticated]) def get_recommendations(request): """Personalisiertes Empfehlungen für User""" try: # Get user profile profile, created = UserProfile.objects.get_or_create(user=request.user) # Get recommendations recommendation_service = RecommendationService() recommendations = recommendation_service.get_recommendations_for_user(request.user) # Track recommendation view UserBehavior.objects.create( user=request.user, behavior_type='view', metadata={'recommendation_count': len(recommendations)} ) return Response({ 'recommendations': recommendations, 'user_profile': { 'engagement_score': profile.engagement_score, 'loyalty_level': profile.loyalty_level, 'preferred_categories': profile.preferred_categories, } }) except Exception as e: return Response({'error': str(e)}, status=500) @api_view(['GET']) @permission_classes([IsAuthenticated]) def get_similar_products(request, product_id): """Ähnliche Produkte für ein spezifisches Produkt""" try: from products.models import Product product = Product.objects.get(id=product_id) # Get similar products similar_products = ProductSimilarity.objects.filter( product=product ).select_related('similar_product').order_by('-similarity_score')[:10] recommendations = [] for similarity in similar_products: recommendations.append({ 'product': { 'id': similarity.similar_product.id, 'name': similarity.similar_product.name, 'price': float(similarity.similar_product.price), 'image_url': similarity.similar_product.image.url if similarity.similar_product.image else None, }, 'similarity_score': similarity.similarity_score, 'similarity_type': similarity.similarity_type, 'reason': f"Ähnlich zu {product.name}" }) return Response({'similar_products': recommendations}) except Product.DoesNotExist: return Response({'error': 'Product not found'}, status=404) except Exception as e: return Response({'error': str(e)}, status=500) @api_view(['POST']) @permission_classes([IsAuthenticated]) def track_behavior(request): """User Behavior tracken""" try: data = request.data behavior_type = data.get('behavior_type') product_id = data.get('product_id') auction_id = data.get('auction_id') metadata = data.get('metadata', {}) if not behavior_type: return Response({'error': 'Behavior type required'}, status=400) # Create behavior record behavior = UserBehavior.objects.create( user=request.user, behavior_type=behavior_type, product_id=product_id, auction_id=auction_id, session_id=data.get('session_id', ''), ip_address=request.META.get('REMOTE_ADDR'), user_agent=request.META.get('HTTP_USER_AGENT', ''), metadata=metadata ) # Update user profile profile, created = UserProfile.objects.get_or_create(user=request.user) profile.update_engagement_score() return Response({'behavior_id': str(behavior.id)}) except Exception as e: return Response({'error': str(e)}, status=500) @api_view(['GET']) @permission_classes([IsAuthenticated]) def get_user_profile(request): """User Profile für Empfehlungen abrufen""" try: profile, created = UserProfile.objects.get_or_create(user=request.user) return Response({ 'engagement_score': profile.engagement_score, 'loyalty_level': profile.loyalty_level, 'preferred_categories': profile.preferred_categories, 'preferred_fursuit_types': profile.preferred_fursuit_types, 'preferred_price_range': profile.preferred_price_range, 'total_purchases': profile.total_purchases, 'total_views': profile.total_views, 'last_active': profile.last_active, }) except Exception as e: return Response({'error': str(e)}, status=500) @api_view(['POST']) @permission_classes([IsAuthenticated]) def update_user_preferences(request): """User Preferences aktualisieren""" try: data = request.data profile, created = UserProfile.objects.get_or_create(user=request.user) # Update preferences if 'preferred_categories' in data: profile.preferred_categories = data['preferred_categories'] if 'preferred_fursuit_types' in data: profile.preferred_fursuit_types = data['preferred_fursuit_types'] if 'preferred_price_range' in data: profile.preferred_price_range = data['preferred_price_range'] if 'preferred_colors' in data: profile.preferred_colors = data['preferred_colors'] profile.save() return Response({'message': 'Preferences updated'}) except Exception as e: return Response({'error': str(e)}, status=500) @api_view(['GET']) @permission_classes([IsAuthenticated]) def get_popular_products(request): """Beliebte Produkte basierend auf Verhalten""" try: # Get popular products based on behavior popular_products = Product.objects.annotate( view_count=Count('behaviors', filter=Q(behaviors__behavior_type='view')), purchase_count=Count('behaviors', filter=Q(behaviors__behavior_type='purchase')), cart_count=Count('behaviors', filter=Q(behaviors__behavior_type='cart_add')), ).filter( is_active=True ).order_by('-purchase_count', '-view_count')[:10] recommendations = [] for product in popular_products: recommendations.append({ 'product': { 'id': product.id, 'name': product.name, 'price': float(product.price), 'image_url': product.image.url if product.image else None, 'category': product.category, }, 'popularity_score': product.purchase_count + (product.view_count * 0.1), 'reason': 'Beliebt bei anderen Kunden' }) return Response({'popular_products': recommendations}) except Exception as e: return Response({'error': str(e)}, status=500) @api_view(['GET']) @permission_classes([IsAuthenticated]) def get_trending_products(request): """Trending Produkte (recent activity)""" try: # Get trending products (recent activity) from datetime import timedelta recent_date = timezone.now() - timedelta(days=7) trending_products = Product.objects.annotate( recent_views=Count('behaviors', filter=Q( behaviors__behavior_type='view', behaviors__created_at__gte=recent_date )), recent_purchases=Count('behaviors', filter=Q( behaviors__behavior_type='purchase', behaviors__created_at__gte=recent_date )), ).filter( is_active=True, recent_views__gt=0 ).order_by('-recent_purchases', '-recent_views')[:10] recommendations = [] for product in trending_products: recommendations.append({ 'product': { 'id': product.id, 'name': product.name, 'price': float(product.price), 'image_url': product.image.url if product.image else None, 'category': product.category, }, 'trending_score': product.recent_purchases + (product.recent_views * 0.1), 'reason': 'Trending diese Woche' }) return Response({'trending_products': recommendations}) except Exception as e: return Response({'error': str(e)}, status=500) @api_view(['GET']) @permission_classes([IsAuthenticated]) def get_frequently_bought_together(request, product_id): """Häufig zusammen gekaufte Produkte""" try: from products.models import Product product = Product.objects.get(id=product_id) # Get users who bought this product buyers = UserBehavior.objects.filter( product=product, behavior_type='purchase' ).values_list('user', flat=True).distinct() # Get other products bought by same users frequently_bought = Product.objects.filter( behaviors__user__in=buyers, behaviors__behavior_type='purchase' ).exclude(id=product_id).annotate( bought_together_count=Count('behaviors', filter=Q( behaviors__behavior_type='purchase', behaviors__user__in=buyers )) ).filter( bought_together_count__gt=0, is_active=True ).order_by('-bought_together_count')[:5] recommendations = [] for product in frequently_bought: recommendations.append({ 'product': { 'id': product.id, 'name': product.name, 'price': float(product.price), 'image_url': product.image.url if product.image else None, }, 'bought_together_count': product.bought_together_count, 'reason': 'Häufig zusammen gekauft' }) return Response({'frequently_bought_together': recommendations}) except Product.DoesNotExist: return Response({'error': 'Product not found'}, status=404) except Exception as e: return Response({'error': str(e)}, status=500) @api_view(['POST']) @permission_classes([IsAuthenticated]) def track_recommendation_click(request): """Recommendation Click tracken""" try: data = request.data product_id = data.get('product_id') recommendation_type = data.get('recommendation_type') if not product_id or not recommendation_type: return Response({'error': 'Product ID and recommendation type required'}, status=400) # Update recommendation recommendation = Recommendation.objects.filter( user=request.user, product_id=product_id, recommendation_type=recommendation_type ).first() if recommendation: recommendation.is_clicked = True recommendation.save() # Track behavior UserBehavior.objects.create( user=request.user, behavior_type='view', product_id=product_id, metadata={'recommendation_type': recommendation_type} ) return Response({'success': True}) except Exception as e: return Response({'error': str(e)}, status=500) @api_view(['POST']) @permission_classes([IsAuthenticated]) def track_recommendation_purchase(request): """Recommendation Purchase tracken""" try: data = request.data product_id = data.get('product_id') recommendation_type = data.get('recommendation_type') if not product_id or not recommendation_type: return Response({'error': 'Product ID and recommendation type required'}, status=400) # Update recommendation recommendation = Recommendation.objects.filter( user=request.user, product_id=product_id, recommendation_type=recommendation_type ).first() if recommendation: recommendation.is_purchased = True recommendation.save() # Track behavior UserBehavior.objects.create( user=request.user, behavior_type='purchase', product_id=product_id, metadata={'recommendation_type': recommendation_type} ) return Response({'success': True}) except Exception as e: return Response({'error': str(e)}, status=500) # Admin Views @login_required def recommendation_dashboard(request): """Admin Dashboard für Empfehlungen""" if not request.user.is_staff: return JsonResponse({'error': 'Access denied'}, status=403) # Get analytics today_analytics = RecommendationAnalytics.get_or_create_today() # Get recent behaviors recent_behaviors = UserBehavior.objects.select_related('user', 'product').order_by('-created_at')[:20] # Get active models active_models = RecommendationModel.objects.filter(is_active=True) # Get A/B tests active_tests = ABTest.objects.filter(status='running') context = { 'today_analytics': today_analytics, 'recent_behaviors': recent_behaviors, 'active_models': active_models, 'active_tests': active_tests, } return render(request, 'recommendations/dashboard.html', context) @login_required def recommendation_analytics(request): """Recommendation Analytics""" if not request.user.is_staff: return JsonResponse({'error': 'Access denied'}, status=403) # Get analytics for last 30 days from datetime import timedelta analytics = RecommendationAnalytics.objects.filter( date__gte=timezone.now().date() - timedelta(days=30) ).order_by('date') # Calculate totals total_recommendations = sum(a.total_recommendations for a in analytics) total_clicks = sum(a.total_clicks for a in analytics) total_purchases = sum(a.total_purchases for a in analytics) total_revenue = sum(a.revenue_from_recommendations for a in analytics) context = { 'analytics': analytics, 'totals': { 'recommendations': total_recommendations, 'clicks': total_clicks, 'purchases': total_purchases, 'revenue': total_revenue, 'ctr': (total_clicks / total_recommendations * 100) if total_recommendations > 0 else 0, 'conversion_rate': (total_purchases / total_clicks * 100) if total_clicks > 0 else 0, } } return render(request, 'recommendations/analytics.html', context)