""" AI Engine API views """ import time from django.db.models import Q from drf_spectacular.utils import extend_schema, extend_schema_view from rest_framework import status, viewsets from rest_framework.decorators import action, api_view, permission_classes from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from apps.accounts.permissions import IsPXAdmin, IsHospitalAdmin from .models import SentimentResult from .serializers import ( AnalyzeTextRequestSerializer, AnalyzeTextResponseSerializer, BatchAnalyzeRequestSerializer, BatchAnalyzeResponseSerializer, SentimentResultSerializer, SentimentStatsSerializer, ) from .services import AIEngineService @extend_schema_view( list=extend_schema( summary="List sentiment results", description="Get a list of all sentiment analysis results with filtering options" ), retrieve=extend_schema( summary="Get sentiment result", description="Get details of a specific sentiment analysis result" ), ) class SentimentResultViewSet(viewsets.ReadOnlyModelViewSet): """ Sentiment result viewset - Read-only API for sentiment results. Provides: - List all sentiment results with filters - Retrieve specific sentiment result - Statistics endpoint """ serializer_class = SentimentResultSerializer permission_classes = [IsAuthenticated] filterset_fields = ['sentiment', 'language', 'ai_service'] search_fields = ['text'] ordering_fields = ['created_at', 'sentiment_score', 'confidence'] ordering = ['-created_at'] def get_queryset(self): """Filter queryset based on user permissions""" queryset = SentimentResult.objects.select_related('content_type').all() # Apply filters from query params sentiment = self.request.query_params.get('sentiment') if sentiment: queryset = queryset.filter(sentiment=sentiment) language = self.request.query_params.get('language') if language: queryset = queryset.filter(language=language) ai_service = self.request.query_params.get('ai_service') if ai_service: queryset = queryset.filter(ai_service=ai_service) min_confidence = self.request.query_params.get('min_confidence') if min_confidence: queryset = queryset.filter(confidence__gte=min_confidence) search = self.request.query_params.get('search') if search: queryset = queryset.filter(text__icontains=search) return queryset @extend_schema( summary="Get sentiment statistics", description="Get aggregated statistics for sentiment results", responses={200: SentimentStatsSerializer} ) @action(detail=False, methods=['get']) def stats(self, request): """Get sentiment statistics""" queryset = self.get_queryset() stats = AIEngineService.get_sentiment_stats(queryset) serializer = SentimentStatsSerializer(stats) return Response(serializer.data) @extend_schema( summary="Analyze text", description="Analyze text for sentiment, keywords, entities, and emotions", request=AnalyzeTextRequestSerializer, responses={200: AnalyzeTextResponseSerializer} ) @api_view(['POST']) @permission_classes([IsAuthenticated]) def analyze_text(request): """ Analyze text for sentiment. POST /api/ai-engine/analyze/ Request body: { "text": "The service was excellent!", "language": "en", // optional, auto-detected if not provided "extract_keywords": true, "extract_entities": true, "detect_emotions": true } Response: { "text": "The service was excellent!", "language": "en", "sentiment": "positive", "sentiment_score": 0.8, "confidence": 0.9, "keywords": ["excellent"], "entities": [], "emotions": {"joy": 0.6}, "ai_service": "stub", "ai_model": "keyword_matching_v1", "processing_time_ms": 5 } """ serializer = AnalyzeTextRequestSerializer(data=request.data) if not serializer.is_valid(): return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST ) # Perform analysis result = AIEngineService.sentiment.analyze_text( text=serializer.validated_data['text'], language=serializer.validated_data.get('language'), extract_keywords=serializer.validated_data.get('extract_keywords', True), extract_entities=serializer.validated_data.get('extract_entities', True), detect_emotions=serializer.validated_data.get('detect_emotions', True), ) response_serializer = AnalyzeTextResponseSerializer(result) return Response(response_serializer.data) @extend_schema( summary="Analyze batch of texts", description="Analyze multiple texts in a single request", request=BatchAnalyzeRequestSerializer, responses={200: BatchAnalyzeResponseSerializer} ) @api_view(['POST']) @permission_classes([IsAuthenticated]) def analyze_batch(request): """ Analyze multiple texts in batch. POST /api/ai-engine/analyze-batch/ Request body: { "texts": [ "The service was excellent!", "Very disappointed with the wait time.", "Average experience overall." ], "language": "en" // optional } Response: { "results": [ { "text": "The service was excellent!", "sentiment": "positive", ... }, ... ], "total": 3, "processing_time_ms": 15 } """ serializer = BatchAnalyzeRequestSerializer(data=request.data) if not serializer.is_valid(): return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST ) start_time = time.time() # Perform batch analysis results = AIEngineService.sentiment.analyze_batch( texts=serializer.validated_data['texts'], language=serializer.validated_data.get('language'), ) processing_time_ms = int((time.time() - start_time) * 1000) response_data = { 'results': results, 'total': len(results), 'processing_time_ms': processing_time_ms, } response_serializer = BatchAnalyzeResponseSerializer(response_data) return Response(response_serializer.data) @extend_schema( summary="Get sentiment for object", description="Get sentiment analysis result for a specific object", responses={200: SentimentResultSerializer} ) @api_view(['GET']) @permission_classes([IsAuthenticated]) def get_sentiment_for_object(request, content_type_id, object_id): """ Get sentiment result for a specific object. GET /api/ai-engine/sentiment/{content_type_id}/{object_id}/ """ from django.contrib.contenttypes.models import ContentType try: content_type = ContentType.objects.get(id=content_type_id) except ContentType.DoesNotExist: return Response( {'error': 'Content type not found'}, status=status.HTTP_404_NOT_FOUND ) sentiment_result = SentimentResult.objects.filter( content_type=content_type, object_id=object_id ).first() if not sentiment_result: return Response( {'error': 'Sentiment result not found'}, status=status.HTTP_404_NOT_FOUND ) serializer = SentimentResultSerializer(sentiment_result) return Response(serializer.data)