import time import uuid from datetime import timedelta from django.utils import timezone from rest_framework import status, viewsets from rest_framework.decorators import action, api_view, permission_classes from rest_framework.response import Response from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework_simplejwt.tokens import RefreshToken from django.db.models import Count, Q from django.http import JsonResponse from .models import AIAgent, AIOperationLog, AITask, AIWebhook from .serializers import ( AIAgentSerializer, AIAgentAuthSerializer, AIOperationLogSerializer, AITaskSerializer, AITaskCreateSerializer, AIWebhookSerializer, BatchOperationSerializer ) class AIAgentViewSet(viewsets.ModelViewSet): """AI 代理管理""" queryset = AIAgent.objects.all() serializer_class = AIAgentSerializer lookup_field = 'agent_id' def get_permissions(self): if self.action == 'auth': return [AllowAny()] return [IsAuthenticated()] @action(detail=False, methods=['post'], permission_classes=[AllowAny]) def auth(self, request): """AI 代理认证""" serializer = AIAgentAuthSerializer(data=request.data) serializer.is_valid(raise_exception=True) agent = serializer.instance # 生成自定义 JWT token(不使用 for_user,因为 AI 不是 Django User) from rest_framework_simplejwt.tokens import AccessToken from datetime import timedelta from django.utils import timezone # 创建 access token access = AccessToken() access['agent_id'] = agent.agent_id access['permissions'] = agent.permissions access['type'] = 'agent' access.set_exp(lifetime=timedelta(hours=1)) # 创建 refresh token from rest_framework_simplejwt.tokens import RefreshToken as BaseRefreshToken class AgentRefreshToken(BaseRefreshToken): token_type = 'refresh' @classmethod def for_agent(cls, agent): token = cls() token['agent_id'] = agent.agent_id token['permissions'] = agent.permissions token['type'] = 'agent' return token refresh = AgentRefreshToken.for_agent(agent) # 记录登录 AIOperationLog.log( agent=agent, action='auth', resource_type='agent', status='success', confidence=1.0, reasoning='Agent authentication successful' ) return Response({ 'access_token': str(access), 'refresh_token': str(refresh), 'expires_in': 3600, 'agent_info': { 'id': agent.agent_id, 'name': agent.name, 'permissions': agent.permissions, 'rate_limit': agent.rate_limit, } }) @action(detail=True, methods=['get']) def stats(self, request, agent_id): """获取代理统计信息""" agent = self.get_object() # 操作统计 operations = AIOperationLog.objects.filter(agent=agent) stats = { 'total_operations': operations.count(), 'success_operations': operations.filter(status='success').count(), 'failed_operations': operations.filter(status='failed').count(), 'avg_confidence': operations.filter(confidence__isnull=False).aggregate( avg=Count('confidence') )['avg'], } # 任务统计 tasks = AITask.objects.filter(agent=agent) stats['tasks'] = { 'total': tasks.count(), 'completed': tasks.filter(status='completed').count(), 'failed': tasks.filter(status='failed').count(), 'processing': tasks.filter(status='processing').count(), } # 最近 7 天操作趋势 from datetime import datetime, timedelta seven_days_ago = timezone.now() - timedelta(days=7) daily_ops = operations.filter( created_at__gte=seven_days_ago ).extra( select={'date': 'date(created_at)'} ).values('date').annotate(count=Count('id')) stats['daily_operations'] = list(daily_ops) return Response(stats) @action(detail=True, methods=['post']) def rotate_secret(self, request, agent_id): """轮换密钥""" agent = self.get_object() agent.secret_key = uuid.uuid4().hex agent.save() AIOperationLog.log( agent=agent, action='rotate_secret', resource_type='agent', status='success' ) return Response({'message': 'Secret key rotated', 'new_secret': agent.secret_key}) class AIOperationLogViewSet(viewsets.ReadOnlyModelViewSet): """AI 操作日志查询""" queryset = AIOperationLog.objects.all() serializer_class = AIOperationLogSerializer def get_queryset(self): queryset = super().get_queryset() # 过滤 agent_id = self.request.query_params.get('agent_id') if agent_id: queryset = queryset.filter(agent__agent_id=agent_id) action = self.request.query_params.get('action') if action: queryset = queryset.filter(action=action) resource_type = self.request.query_params.get('resource_type') if resource_type: queryset = queryset.filter(resource_type=resource_type) status = self.request.query_params.get('status') if status: queryset = queryset.filter(status=status) return queryset @action(detail=False, methods=['get']) def summary(self, request): """操作日志摘要""" # 按代理统计 by_agent = AIOperationLog.objects.values('agent__agent_id', 'agent__name').annotate( total=Count('id'), success=Count('id', filter=Q(status='success')), failed=Count('id', filter=Q(status='failed')) ).order_by('-total') # 按操作类型统计 by_action = AIOperationLog.objects.values('action').annotate( count=Count('id') ).order_by('-count')[:10] # 按资源类型统计 by_resource = AIOperationLog.objects.values('resource_type').annotate( count=Count('id') ).order_by('-count')[:10] return Response({ 'by_agent': list(by_agent), 'by_action': list(by_action), 'by_resource': list(by_resource), 'total': AIOperationLog.objects.count(), }) class AITaskViewSet(viewsets.ModelViewSet): """AI 任务管理""" queryset = AITask.objects.all() serializer_class = AITaskSerializer lookup_field = 'task_id' def get_serializer_class(self): if self.action == 'create': return AITaskCreateSerializer return AITaskSerializer def create(self, request, *args, **kwargs): """创建任务""" serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 获取 AI 代理(从 token 中) agent_id = request.auth.payload.get('agent_id') if hasattr(request, 'auth') else None if not agent_id: return Response({'error': 'Agent authentication required'}, status=401) try: agent = AIAgent.objects.get(agent_id=agent_id) except AIOperationLog.DoesNotExist: return Response({'error': 'Agent not found'}, status=404) # 创建任务 task = AITask.objects.create( task_id=uuid.uuid4().hex, agent=agent, task_type=serializer.validated_data['task_type'], status='pending', callback_url=serializer.validated_data.get('callback_url') ) # TODO: 将任务加入队列异步处理 # 这里简化处理,如果是 batch 任务,立即处理 if task.task_type == 'batch': operations = serializer.validated_data.get('operations', []) # 异步处理会在这里触发 task.status = 'processing' task.started_at = timezone.now() task.total_items = len(operations) task.save() return Response(AITaskSerializer(task).data, status=201) @action(detail=True, methods=['post']) def cancel(self, request, task_id): """取消任务""" task = self.get_object() if task.status in ['completed', 'failed']: return Response({'error': 'Task already completed'}, status=400) task.status = 'cancelled' task.completed_at = timezone.now() task.save() return Response({'message': 'Task cancelled'}) @api_view(['POST']) def batch_execute(request): """批量操作执行""" serializer = BatchOperationSerializer(data=request.data) serializer.is_valid(raise_exception=True) operations = serializer.validated_data['operations'] results = [] # 获取 AI 代理 agent_id = request.auth.payload.get('agent_id') if hasattr(request, 'auth') else None if not agent_id: return Response({'error': 'Agent authentication required'}, status=401) try: agent = AIAgent.objects.get(agent_id=agent_id) except AIAgent.DoesNotExist: return Response({'error': 'Agent not found'}, status=404) # 检查批量操作权限 if not agent.has_permission('batch'): return Response({'error': 'No batch permission'}, status=403) start_time = time.time() # 执行操作(简化版本,实际应该异步) for i, op in enumerate(operations): try: # TODO: 实际执行 HTTP 请求到对应的 API # 这里只记录日志 AIOperationLog.log( agent=agent, action=f"batch_{op['method'].lower()}", resource_type='batch', status='success', request_data=op, execution_time_ms=int((time.time() - start_time) * 1000) ) results.append({ 'index': i, 'status': 'success', 'method': op['method'], 'path': op['path'] }) except Exception as e: results.append({ 'index': i, 'status': 'failed', 'error': str(e) }) execution_time = int((time.time() - start_time) * 1000) # 记录批量操作日志 AIOperationLog.log( agent=agent, action='batch_execute', resource_type='batch', status='success', confidence=1.0, reasoning=f'Executed {len(operations)} operations', request_data={'operations_count': len(operations)}, execution_time_ms=execution_time ) return Response({ 'task_id': uuid.uuid4().hex, 'status': 'completed', 'execution_time_ms': execution_time, 'results': results, 'summary': { 'total': len(operations), 'success': sum(1 for r in results if r['status'] == 'success'), 'failed': sum(1 for r in results if r['status'] == 'failed') } }) class AIWebhookViewSet(viewsets.ModelViewSet): """AI Webhook 管理""" queryset = AIWebhook.objects.all() serializer_class = AIWebhookSerializer def get_queryset(self): queryset = super().get_queryset() # 只返回当前代理的 webhook agent_id = self.request.auth.payload.get('agent_id') if hasattr(self.request, 'auth') else None if agent_id: queryset = queryset.filter(agent__agent_id=agent_id) return queryset def perform_create(self, serializer): # 自动关联当前代理 agent_id = self.request.auth.payload.get('agent_id') if hasattr(self.request, 'auth') else None if agent_id: agent = AIAgent.objects.get(agent_id=agent_id) serializer.save(agent=agent)