learningAnalyticsUrl = config('services.learning_analytics.base_url', env('LEARNING_ANALYTICS_URL', 'http://localhost:5016')); $this->timeout = 180; // ChatGPT分析超时 } /** * 使用ChatGPT分析试卷图片 * * @param string $paperId 试卷ID * @param string $imageUrl 试卷图片URL * @return array 分析结果 */ public function analyzeExamPaper(string $paperId, string $imageUrl): array { try { Log::info('开始ChatGPT分析', [ 'paper_id' => $paperId, 'image_url' => $imageUrl ]); // 获取题目数据 $questionsData = $this->getPaperQuestions($paperId); if (empty($questionsData)) { throw new \Exception('未找到试卷题目'); } // 调用LearningAnalytics的ChatGPT分析API $requestData = [ 'paper_id' => $paperId, 'questions' => $questionsData, 'image_url' => $imageUrl, 'student_id' => $this->getStudentId($paperId), ]; Log::info('调用LearningAnalytics ChatGPT分析API', [ 'url' => $this->learningAnalyticsUrl . '/api/v1/chatgpt/analyze', 'question_count' => count($questionsData) ]); $response = Http::timeout($this->timeout) ->post($this->learningAnalyticsUrl . '/api/v1/chatgpt/analyze', $requestData); if (!$response->successful()) { throw new \Exception('LearningAnalytics API调用失败: ' . $response->body()); } $responseData = $response->json(); Log::info('ChatGPT分析完成', [ 'paper_id' => $paperId, 'questions_count' => count($responseData['questions'] ?? []), 'success' => true ]); return [ 'success' => true, 'data' => $responseData, ]; } catch (\Exception $e) { Log::error('ChatGPT分析失败', [ 'paper_id' => $paperId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return [ 'success' => false, 'error' => $e->getMessage(), 'data' => null ]; } } /** * 获取试卷题目 */ private function getPaperQuestions(string $paperId): array { try { // 处理OCR记录 if (str_starts_with($paperId, 'ocr_')) { $recordId = substr($paperId, 4); $ocrQuestions = DB::table('ocr_question_results') ->where('ocr_record_id', $recordId) ->orderBy('question_number') ->get() ->map(function ($q) { // 优先使用人工校准的答案 $studentAnswer = !empty(trim($q->manual_answer ?? '')) ? trim($q->manual_answer) : trim($q->student_answer ?? ''); return [ 'question_number' => $q->question_number, 'question_id' => $q->question_number, 'content' => $q->question_text, 'correct_answer' => '', // ChatGPT会从图片识别 'knowledge_point' => $q->kp_code, 'question_type' => 'unknown', 'score' => $q->score_total ?? 5 ]; }) ->toArray(); return $ocrQuestions; } // 处理系统生成卷子 $questions = DB::table('paper_questions') ->where('paper_id', $paperId) ->orderBy('question_number') ->get() ->map(function ($q) { return [ 'question_number' => $q->question_number, 'question_id' => $q->question_bank_id, 'content' => $q->question_text, 'correct_answer' => '', // ChatGPT会从图片识别 'knowledge_point' => $q->knowledge_point, 'question_type' => $q->question_type, 'score' => $q->score ]; }) ->toArray(); return $questions; } catch (\Exception $e) { Log::error('获取试卷题目失败', [ 'paper_id' => $paperId, 'error' => $e->getMessage() ]); return []; } } /** * 获取学生ID */ private function getStudentId(string $paperId): ?string { try { // 处理OCR记录 if (str_starts_with($paperId, 'ocr_')) { $recordId = substr($paperId, 4); $record = DB::table('ocr_records')->where('id', $recordId)->first(); return $record->student_id ?? null; } // 处理系统生成卷子 $paper = DB::table('papers')->where('paper_id', $paperId)->first(); return $paper->student_id ?? null; } catch (\Exception $e) { Log::error('获取学生ID失败', [ 'paper_id' => $paperId, 'error' => $e->getMessage() ]); return null; } } /** * 保存ChatGPT分析结果到数据库 */ public function saveAnalysisResult(string $paperId, array $analysisData): bool { try { return DB::transaction(function () use ($paperId, $analysisData) { // 更新papers表的analysis_id DB::table('papers') ->where('paper_id', $paperId) ->update([ 'analysis_id' => $analysisData['analysis_id'] ?? ('chatgpt_' . uniqid()), 'updated_at' => now() ]); // 保存详细分析结果到answer_analysis表 if (isset($analysisData['questions'])) { foreach ($analysisData['questions'] as $questionData) { $questionNumber = $questionData['q'] ?? null; if (!$questionNumber) continue; // 查找对应的paper_question记录 $paperQuestion = null; if (str_starts_with($paperId, 'ocr_')) { // OCR记录使用question_number作为ID $paperQuestion = (object)[ 'question_bank_id' => 'ocr_q' . $questionNumber, 'score' => 5 ]; } else { $paperQuestion = DB::table('paper_questions') ->where('paper_id', $paperId) ->where('question_number', $questionNumber) ->first(); } if ($paperQuestion) { DB::table('answer_analysis')->updateOrInsert( [ 'paper_id' => $paperId, 'question_id' => $paperQuestion->question_bank_id, 'question_number' => $questionNumber, ], [ 'student_answer' => $questionData['student_answer'] ?? null, 'correct_answer' => $questionData['correct_answer'] ?? null, 'is_correct' => $questionData['is_correct'] ?? false, 'score_obtained' => $questionData['is_correct'] ? ($paperQuestion->score ?? 0) : 0, 'max_score' => $paperQuestion->score ?? 0, 'analysis_result' => json_encode($questionData, JSON_UNESCAPED_UNICODE), 'updated_at' => now() ] ); } } } Log::info('ChatGPT分析结果保存成功', [ 'paper_id' => $paperId, 'questions_count' => count($analysisData['questions'] ?? []) ]); return true; }); } catch (\Exception $e) { Log::error('保存ChatGPT分析结果失败', [ 'paper_id' => $paperId, 'error' => $e->getMessage() ]); return false; } } }