255 lines
7.6 KiB
Python
255 lines
7.6 KiB
Python
"""
|
|
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)
|