'mysql']); echo "\n" . str_repeat("=", 80) . "\n"; echo "🧪 OCR题目分析测试\n"; echo str_repeat("=", 80) . "\n\n"; // 1. 从数据库获取OCR题目 $recordId = 12; echo "📚 从数据库读取OCR记录 #{$recordId} 的题目...\n"; $ocrQuestions = OCRQuestionResult::where('ocr_record_id', $recordId) ->orderBy('question_number') ->get(); if ($ocrQuestions->isEmpty()) { echo "❌ 未找到OCR记录 {$recordId} 的题目数据\n"; $this->fail("No OCR questions found for record {$recordId}"); return; } echo "✅ 获取到 {$ocrQuestions->count()} 道题目\n\n"; // 2. 构建请求数据 $questions = []; foreach ($ocrQuestions as $oq) { // 使用校准后的答案,如果没有则使用OCR识别的答案 $studentAnswer = !empty($oq->manual_answer) ? $oq->manual_answer : $oq->student_answer; $questions[] = [ 'question_number' => $oq->question_number, 'question_text' => $oq->question_text ?? '', 'student_answer' => $studentAnswer ?? '' ]; } // 3. 调用题库API echo "📤 发送请求到题库API: http://localhost:5015/api/questions/analyze-ocr\n"; echo "题目数量: " . count($questions) . "\n\n"; echo "题目列表:\n"; foreach ($questions as $i => $q) { $preview = mb_substr($q['question_text'], 0, 50); echo " " . ($i + 1) . ". {$preview}...\n"; echo " 学生答案: {$q['student_answer']}\n"; } echo "\n"; echo "🤖 调用AI分析中,请稍候...\n\n"; $response = Http::timeout(120)->post('http://localhost:5015/api/questions/analyze-ocr', [ 'questions' => $questions, 'grade_level' => '高一', 'subject' => '数学' ]); // 4. 检查响应 if (!$response->successful()) { echo "❌ API调用失败\n"; echo "状态码: {$response->status()}\n"; echo "响应: " . $response->body() . "\n"; $this->fail("API call failed with status " . $response->status()); return; } $result = $response->json(); if ($result['status'] !== 'success') { echo "❌ 分析失败: " . ($result['message'] ?? 'Unknown error') . "\n"; $this->fail("Analysis failed: " . ($result['message'] ?? 'Unknown error')); return; } // 5. 显示分析结果 echo str_repeat("=", 80) . "\n"; echo "📊 分析结果\n"; echo str_repeat("=", 80) . "\n\n"; echo "✅ 分析成功,使用模型: " . ($result['model_used'] ?? 'unknown') . "\n\n"; $analyzedQuestions = $result['questions'] ?? []; foreach ($ocrQuestions as $index => $original) { if (!isset($analyzedQuestions[$index])) { continue; } $analyzed = $analyzedQuestions[$index]; echo str_repeat("=", 60) . "\n"; echo "题目 " . ($index + 1) . "\n"; echo str_repeat("=", 60) . "\n\n"; // 原始题目 echo "📝 原始题目:\n"; $questionText = $original->question_text ?? ''; $preview = mb_substr($questionText, 0, 100); echo " {$preview}...\n\n"; // 学生答案vs标准答案 $studentAnswer = !empty($original->manual_answer) ? $original->manual_answer : $original->student_answer; echo "👤 学生答案: {$studentAnswer}\n"; echo "✓ 标准答案: " . ($analyzed['answer'] ?? 'N/A') . "\n"; $isCorrect = $analyzed['is_correct'] ?? false; echo " 判断结果: " . ($isCorrect ? '✓ 正确' : '✗ 错误') . "\n\n"; // 知识点匹配 echo "🎯 知识点匹配:\n"; echo " 主知识点: " . ($analyzed['kp_code'] ?? 'N/A') . "\n"; echo " 全部知识点: " . implode(', ', $analyzed['kp_codes'] ?? []) . "\n"; echo " 匹配度: " . ($analyzed['kp_similarity'] ?? 'N/A') . "\n\n"; // 题目属性 echo "📊 题目属性:\n"; echo " 题型: " . ($analyzed['question_type'] ?? 'N/A') . "\n"; echo " 难度: " . ($analyzed['difficulty'] ?? 'N/A') . "\n\n"; // 解析 echo "💡 解析:\n"; $solution = $analyzed['solution'] ?? 'N/A'; $solutionPreview = mb_substr($solution, 0, 150); echo " {$solutionPreview}" . (mb_strlen($solution) > 150 ? '...' : '') . "\n\n"; // 错误说明 if (!$isCorrect && !empty($analyzed['explanation'])) { echo "⚠️ 错误说明:\n"; $explanation = $analyzed['explanation']; $explanationPreview = mb_substr($explanation, 0, 150); echo " {$explanationPreview}" . (mb_strlen($explanation) > 150 ? '...' : '') . "\n\n"; } // 题库状态 echo "💾 题库状态:\n"; echo " 题目ID: " . ($analyzed['question_bank_id'] ?? 'N/A') . "\n"; echo " 已保存: " . ($analyzed['saved_to_db'] ? '是' : '否(已存在)') . "\n\n"; } echo str_repeat("=", 80) . "\n"; echo "✅ 测试完成\n"; echo str_repeat("=", 80) . "\n\n"; // 断言:确保所有题目都得到了分析 $this->assertEquals(count($questions), count($analyzedQuestions), "分析的题目数量应该与输入相同"); // 断言:每道题都有标准答案 foreach ($analyzedQuestions as $q) { $this->assertNotEmpty($q['answer'], "题目 {$q['question_number']} 应该有标准答案"); $this->assertNotEmpty($q['kp_code'], "题目 {$q['question_number']} 应该有知识点"); } } }