Guest User

Untitled

a guest
Jul 24th, 2025
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.50 KB | None | 0 0
  1. @csrf_protect
  2. @api_view(['POST'])
  3. @permission_classes([IsAuthenticated])
  4. async def generate_report_batch(request):
  5.     """
  6.    Handles the creation and async generation of multiple reports.
  7.    """
  8.     logger.debug(f"Async batch generation request received with data: {request.data}")
  9.    
  10.     student_reports_data = request.data.get('reports')
  11.     word_count = request.data.get('word_count')
  12.  
  13.     if not isinstance(student_reports_data, dict) or not word_count:
  14.         return Response({'error': 'Invalid payload format. "reports" and "word_count" are required.'}, status=status.HTTP_400_BAD_REQUEST)
  15.  
  16.     report_list_data = list(student_reports_data.values())
  17.     batch_size = len(report_list_data)
  18.  
  19.     if not request.user.institution.can_generate() or request.user.institution.remaining_reports < batch_size:
  20.         return Response({'error': 'Not enough report tokens to generate the entire batch.'}, status=status.HTTP_402_PAYMENT_REQUIRED)
  21.  
  22.     # Report configuration entries
  23.     created_reports = []
  24.     all_serializers_valid = True
  25.     errors = []
  26.    
  27.     for report_data in report_list_data:
  28.         serializer = ReportSerializer(data=report_data, context={'request': request})
  29.         if serializer.is_valid():
  30.             try:
  31.                 student = await Student.objects.aget(pk=report_data.get('student'))
  32.                 if student.institution != request.user.institution:
  33.                     raise Http404
  34.                
  35.                 report_instance = await serializer.asave(user=request.user)
  36.                 created_reports.append(report_instance)
  37.                 errors.append({})
  38.             except (Student.DoesNotExist, Http404):
  39.                 all_serializers_valid = False
  40.                 errors.append({'student': 'Student not found or does not belong to your institution.'})
  41.         else:
  42.             all_serializers_valid = False
  43.             errors.append(serializer.errors)
  44.  
  45.     if not all_serializers_valid:
  46.         await Report.objects.filter(id__in=[r.id for r in created_reports]).adelete()
  47.         return Response({'error': 'Validation failed for one or more reports.', 'details': errors}, status=status.HTTP_400_BAD_REQUEST)
  48.  
  49.     # Prepare and run CONCURRENT LLM calls
  50.     tasks = []
  51.     for report in created_reports:
  52.         student_details = report.create_prompt()
  53.         # Creating a coroutine for each API call and adding it to task list
  54.         tasks.append(prompt.call_ai_async(student_details, word_count))
  55.  
  56.     # return_exceptions=True so that one failure won't stop the others.
  57.     ai_results = await asyncio.gather(*tasks, return_exceptions=True)
  58.  
  59.     # Process results and save GeneratedReport objects
  60.     final_response_data = {}
  61.     successful_reports = 0
  62.     total_usage = {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0, "total_spending_usd": Decimal(0), "total_spending_gbp": Decimal(0)}
  63.  
  64.     for i, result in enumerate(ai_results):
  65.         report_instance = created_reports[i] # Matching result to the original report by index
  66.  
  67.         if isinstance(result, Exception):
  68.             logger.error(f"Error generating report for report_id {report_instance.id}: {result}")
  69.             continue # move to the next
  70.  
  71.         # Process successful result
  72.         usage = prompt.get_token_usage_and_cost(result)
  73.         for key in total_usage: # Aggregate usage stats
  74.             total_usage[key] += usage[key]
  75.  
  76.         student_report_text = result.choices[0].message.content.strip()
  77.         de_anon_report = report_instance.de_anon_report(student_report_text)
  78.         report_word_count = len(de_anon_report.split())
  79.         report_char_count = len(de_anon_report)
  80.  
  81.         gen_report_data = {
  82.             'student_id': report_instance.student.id,
  83.             'user': request.user.id,
  84.             'report': report_instance.id,
  85.             'report_content': de_anon_report,
  86.             'word_count': report_word_count,
  87.             'char_count': report_char_count,
  88.             'batch_mode': True
  89.         }
  90.  
  91.         gen_report_serializer = GeneratedReportSerializer(data=gen_report_data, context={'request': request})
  92.         if gen_report_serializer.is_valid():
  93.             saved_gen_report = await gen_report_serializer.asave()
  94.             # Must serialize the saved instance to include all fields (like student object)
  95.             final_response_data[report_instance.id] = GeneratedReportSerializer(saved_gen_report, context={'request': request}).data
  96.             successful_reports += 1
  97.         else:
  98.             logger.error(f"Failed to serialize generated report for report_id {report_instance.id}: {gen_report_serializer.errors}")
  99.  
  100.     # Adjusting usage counts based on successful reports
  101.     if successful_reports > 0:
  102.         user = request.user
  103.         await user.institution.aincrement_reports_used(count=successful_reports)
  104.         await user.aincrement_generated_count(count=successful_reports)
  105.  
  106.         await User.objects.filter(pk=user.pk).aupdate(
  107.             total_input_tokens=F('total_input_tokens') + total_usage["input_tokens"],
  108.             total_output_tokens=F('total_output_tokens') + total_usage["output_tokens"],
  109.             total_tokens=F('total_tokens') + total_usage["total_tokens"],
  110.             total_spending_usd=Coalesce(F('total_spending_usd'), 0, output_field=DecimalField()) + total_usage["total_spending_usd"],
  111.             total_spending_gbp=Coalesce(F('total_spending_gbp'), 0, output_field=DecimalField()) + total_usage["total_spending_gbp"]
  112.         )
  113.  
  114.     return Response(final_response_data, status=status.HTTP_201_CREATED)
Advertisement
Add Comment
Please, Sign In to add comment