OcrQuestionAnalysisTest.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. namespace Tests\Feature;
  3. use Tests\TestCase;
  4. use Illuminate\Support\Facades\Http;
  5. use App\Models\OCRRecord;
  6. use App\Models\OCRQuestionResult;
  7. class OcrQuestionAnalysisTest extends TestCase
  8. {
  9. /**
  10. * 不使用数据库事务,使用真实数据库
  11. */
  12. protected $connectionsToTransact = [];
  13. /**
  14. * 测试OCR题目分析API
  15. *
  16. * 从数据库获取已OCR识别的题目,发送到题库API进行分析
  17. */
  18. public function test_ocr_question_analysis()
  19. {
  20. // 强制使用MySQL连接
  21. config(['database.default' => 'mysql']);
  22. echo "\n" . str_repeat("=", 80) . "\n";
  23. echo "🧪 OCR题目分析测试\n";
  24. echo str_repeat("=", 80) . "\n\n";
  25. // 1. 从数据库获取OCR题目
  26. $recordId = 12;
  27. echo "📚 从数据库读取OCR记录 #{$recordId} 的题目...\n";
  28. $ocrQuestions = OCRQuestionResult::where('ocr_record_id', $recordId)
  29. ->orderBy('question_number')
  30. ->get();
  31. if ($ocrQuestions->isEmpty()) {
  32. echo "❌ 未找到OCR记录 {$recordId} 的题目数据\n";
  33. $this->fail("No OCR questions found for record {$recordId}");
  34. return;
  35. }
  36. echo "✅ 获取到 {$ocrQuestions->count()} 道题目\n\n";
  37. // 2. 构建请求数据
  38. $questions = [];
  39. foreach ($ocrQuestions as $oq) {
  40. // 使用校准后的答案,如果没有则使用OCR识别的答案
  41. $studentAnswer = !empty($oq->manual_answer) ? $oq->manual_answer : $oq->student_answer;
  42. $questions[] = [
  43. 'question_number' => $oq->question_number,
  44. 'question_text' => $oq->question_text ?? '',
  45. 'student_answer' => $studentAnswer ?? ''
  46. ];
  47. }
  48. // 3. 调用题库API
  49. echo "📤 发送请求到题库API: http://localhost:5015/api/questions/analyze-ocr\n";
  50. echo "题目数量: " . count($questions) . "\n\n";
  51. echo "题目列表:\n";
  52. foreach ($questions as $i => $q) {
  53. $preview = mb_substr($q['question_text'], 0, 50);
  54. echo " " . ($i + 1) . ". {$preview}...\n";
  55. echo " 学生答案: {$q['student_answer']}\n";
  56. }
  57. echo "\n";
  58. echo "🤖 调用AI分析中,请稍候...\n\n";
  59. $response = Http::timeout(120)->post('http://localhost:5015/api/questions/analyze-ocr', [
  60. 'questions' => $questions,
  61. 'grade_level' => '高一',
  62. 'subject' => '数学'
  63. ]);
  64. // 4. 检查响应
  65. if (!$response->successful()) {
  66. echo "❌ API调用失败\n";
  67. echo "状态码: {$response->status()}\n";
  68. echo "响应: " . $response->body() . "\n";
  69. $this->fail("API call failed with status " . $response->status());
  70. return;
  71. }
  72. $result = $response->json();
  73. if ($result['status'] !== 'success') {
  74. echo "❌ 分析失败: " . ($result['message'] ?? 'Unknown error') . "\n";
  75. $this->fail("Analysis failed: " . ($result['message'] ?? 'Unknown error'));
  76. return;
  77. }
  78. // 5. 显示分析结果
  79. echo str_repeat("=", 80) . "\n";
  80. echo "📊 分析结果\n";
  81. echo str_repeat("=", 80) . "\n\n";
  82. echo "✅ 分析成功,使用模型: " . ($result['model_used'] ?? 'unknown') . "\n\n";
  83. $analyzedQuestions = $result['questions'] ?? [];
  84. foreach ($ocrQuestions as $index => $original) {
  85. if (!isset($analyzedQuestions[$index])) {
  86. continue;
  87. }
  88. $analyzed = $analyzedQuestions[$index];
  89. echo str_repeat("=", 60) . "\n";
  90. echo "题目 " . ($index + 1) . "\n";
  91. echo str_repeat("=", 60) . "\n\n";
  92. // 原始题目
  93. echo "📝 原始题目:\n";
  94. $questionText = $original->question_text ?? '';
  95. $preview = mb_substr($questionText, 0, 100);
  96. echo " {$preview}...\n\n";
  97. // 学生答案vs标准答案
  98. $studentAnswer = !empty($original->manual_answer) ? $original->manual_answer : $original->student_answer;
  99. echo "👤 学生答案: {$studentAnswer}\n";
  100. echo "✓ 标准答案: " . ($analyzed['answer'] ?? 'N/A') . "\n";
  101. $isCorrect = $analyzed['is_correct'] ?? false;
  102. echo " 判断结果: " . ($isCorrect ? '✓ 正确' : '✗ 错误') . "\n\n";
  103. // 知识点匹配
  104. echo "🎯 知识点匹配:\n";
  105. echo " 主知识点: " . ($analyzed['kp_code'] ?? 'N/A') . "\n";
  106. echo " 全部知识点: " . implode(', ', $analyzed['kp_codes'] ?? []) . "\n";
  107. echo " 匹配度: " . ($analyzed['kp_similarity'] ?? 'N/A') . "\n\n";
  108. // 题目属性
  109. echo "📊 题目属性:\n";
  110. echo " 题型: " . ($analyzed['question_type'] ?? 'N/A') . "\n";
  111. echo " 难度: " . ($analyzed['difficulty'] ?? 'N/A') . "\n\n";
  112. // 解析
  113. echo "💡 解析:\n";
  114. $solution = $analyzed['solution'] ?? 'N/A';
  115. $solutionPreview = mb_substr($solution, 0, 150);
  116. echo " {$solutionPreview}" . (mb_strlen($solution) > 150 ? '...' : '') . "\n\n";
  117. // 错误说明
  118. if (!$isCorrect && !empty($analyzed['explanation'])) {
  119. echo "⚠️ 错误说明:\n";
  120. $explanation = $analyzed['explanation'];
  121. $explanationPreview = mb_substr($explanation, 0, 150);
  122. echo " {$explanationPreview}" . (mb_strlen($explanation) > 150 ? '...' : '') . "\n\n";
  123. }
  124. // 题库状态
  125. echo "💾 题库状态:\n";
  126. echo " 题目ID: " . ($analyzed['question_bank_id'] ?? 'N/A') . "\n";
  127. echo " 已保存: " . ($analyzed['saved_to_db'] ? '是' : '否(已存在)') . "\n\n";
  128. }
  129. echo str_repeat("=", 80) . "\n";
  130. echo "✅ 测试完成\n";
  131. echo str_repeat("=", 80) . "\n\n";
  132. // 断言:确保所有题目都得到了分析
  133. $this->assertEquals(count($questions), count($analyzedQuestions), "分析的题目数量应该与输入相同");
  134. // 断言:每道题都有标准答案
  135. foreach ($analyzedQuestions as $q) {
  136. $this->assertNotEmpty($q['answer'], "题目 {$q['question_number']} 应该有标准答案");
  137. $this->assertNotEmpty($q['kp_code'], "题目 {$q['question_number']} 应该有知识点");
  138. }
  139. }
  140. }