IntelligentGradingService.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. <?php
  2. namespace App\Services;
  3. use App\Models\OCRRecord;
  4. use App\Models\OCRQuestionResult;
  5. use App\Models\Paper;
  6. use Illuminate\Support\Facades\Http;
  7. use Illuminate\Support\Facades\Log;
  8. class IntelligentGradingService
  9. {
  10. /**
  11. * 对OCR结果进行AI判分(使用分析项目API)
  12. */
  13. public function gradeSubmission(int $ocrRecordId): array
  14. {
  15. $ocrRecord = OCRRecord::findOrFail($ocrRecordId);
  16. $ocrResults = OCRQuestionResult::where('ocr_record_id', $ocrRecordId)->get();
  17. Log::info('开始AI判分', ['ocr_record_id' => $ocrRecordId, 'question_count' => $ocrResults->count()]);
  18. try {
  19. // 调用分析项目API进行判分
  20. $apiUrl = env('LEARNING_ANALYTICS_API', 'http://localhost:8000') . '/api/grade-submission';
  21. $response = Http::timeout(60)->post($apiUrl, [
  22. 'ocr_record_id' => $ocrRecordId,
  23. 'paper_title' => $ocrRecord->paper_title,
  24. 'questions' => $ocrResults->toArray(),
  25. ]);
  26. if (!$response->successful()) {
  27. throw new \Exception('分析API调用失败:' . $response->body());
  28. }
  29. $data = $response->json();
  30. // 更新OCR结果
  31. foreach ($data['question_results'] as $result) {
  32. OCRQuestionResult::where('ocr_record_id', $ocrRecordId)
  33. ->where('question_number', $result['question_number'])
  34. ->update([
  35. 'ai_score' => $result['score'],
  36. 'ai_feedback' => $result['feedback'],
  37. 'ai_confidence' => $result['confidence'] ?? 0.9,
  38. 'ai_analyzed_at' => now(),
  39. ]);
  40. }
  41. // 更新总成绩到papers表(如果存在对应的paper记录)
  42. if (!empty($data['total_score'])) {
  43. $paper = Paper::where('paper_name', $ocrRecord->paper_title)->first();
  44. if ($paper) {
  45. $paper->update(['total_score' => $data['total_score']]);
  46. }
  47. }
  48. Log::info('AI判分完成', [
  49. 'ocr_record_id' => $ocrRecordId,
  50. 'total_score' => $data['total_score'] ?? 0,
  51. ]);
  52. return $data;
  53. } catch (\Exception $e) {
  54. Log::error('AI判分失败', [
  55. 'ocr_record_id' => $ocrRecordId,
  56. 'error' => $e->getMessage(),
  57. ]);
  58. // 使用本地简单判分作为后备
  59. return $this->localGradingFallback($ocrRecordId, $ocrResults);
  60. }
  61. }
  62. /**
  63. * 本地简单判分(后备方案)
  64. */
  65. protected function localGradingFallback(int $ocrRecordId, $ocrResults): array
  66. {
  67. Log::warning('使用本地判分作为后备方案', ['ocr_record_id' => $ocrRecordId]);
  68. $results = [];
  69. $totalScore = 0;
  70. foreach ($ocrResults as $question) {
  71. // 简化判分逻辑:根据答案置信度给分
  72. $score = $question->answer_confidence >= 0.8 ? 5.0 : 2.0;
  73. $question->update([
  74. 'ai_score' => $score,
  75. 'ai_feedback' => '基于置信度的模拟评分',
  76. 'ai_confidence' => $question->answer_confidence,
  77. 'ai_analyzed_at' => now(),
  78. ]);
  79. $results[] = [
  80. 'question_number' => $question->question_number,
  81. 'score' => $score,
  82. 'feedback' => '基于置信度的模拟评分',
  83. 'confidence' => $question->answer_confidence,
  84. ];
  85. $totalScore += $score;
  86. }
  87. return [
  88. 'total_score' => $totalScore,
  89. 'question_results' => $results,
  90. 'method' => 'local_fallback',
  91. ];
  92. }
  93. }