|
|
@@ -55,6 +55,182 @@ Route::post('/questions/callback', function () {
|
|
|
}
|
|
|
})->name('api.questions.callback');
|
|
|
|
|
|
+// 接收OCR题目生成回调
|
|
|
+Route::post('/ocr-question-callback', function () {
|
|
|
+ try {
|
|
|
+ $data = request()->all();
|
|
|
+ Log::info('Received OCR question generation callback', $data);
|
|
|
+
|
|
|
+ // 验证必要的回调数据
|
|
|
+ if (!isset($data['task_id']) || !isset($data['status']) || !isset($data['ocr_record_id'])) {
|
|
|
+ Log::error('OCR callback missing required fields', $data);
|
|
|
+ return response()->json([
|
|
|
+ 'success' => false,
|
|
|
+ 'error' => 'Missing required fields: task_id, status, ocr_record_id'
|
|
|
+ ], 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ $taskId = $data['task_id'];
|
|
|
+ $ocrRecordId = $data['ocr_record_id'];
|
|
|
+ $status = $data['status'];
|
|
|
+
|
|
|
+ // 将回调结果存储到缓存中,供前端查询(保留30秒)
|
|
|
+ $cacheKey = "ocr_callback_{$ocrRecordId}_{$taskId}";
|
|
|
+ cache([$cacheKey => $data], now()->addSeconds(30));
|
|
|
+
|
|
|
+ Log::info("OCR callback cached with key: {$cacheKey}", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'task_id' => $taskId,
|
|
|
+ 'status' => $status,
|
|
|
+ 'total_generated' => $data['result']['total_generated'] ?? 0,
|
|
|
+ 'total_saved' => $data['result']['total_saved'] ?? 0
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 处理题目关联逻辑
|
|
|
+ if ($status === 'completed') {
|
|
|
+ $updatedCount = 0;
|
|
|
+ // 从result中提取question_mappings(QuestionBank API将它放在result字段中)
|
|
|
+ $mappings = $data['result']['question_mappings'] ?? $data['question_mappings'] ?? [];
|
|
|
+
|
|
|
+ Log::info("Processing OCR question associations", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'task_id' => $taskId,
|
|
|
+ 'mappings_count' => count($mappings)
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 更新ocr_question_results表中的关联关系
|
|
|
+ foreach ($mappings as $mapping) {
|
|
|
+ try {
|
|
|
+ $ocrQuestionNumber = $mapping['ocr_question_number'] ?? null;
|
|
|
+ $questionBankId = $mapping['question_bank_id'] ?? null;
|
|
|
+ $questionCode = $mapping['question_code'] ?? null;
|
|
|
+
|
|
|
+ if ($ocrQuestionNumber && $questionBankId) {
|
|
|
+ // 查找对应的OCR题目结果并更新
|
|
|
+ $updated = DB::table('ocr_question_results')
|
|
|
+ ->where('ocr_record_id', $ocrRecordId)
|
|
|
+ ->where('question_number', $ocrQuestionNumber)
|
|
|
+ ->update([
|
|
|
+ 'question_bank_id' => $questionBankId,
|
|
|
+ 'generation_status' => 'completed',
|
|
|
+ 'generation_task_id' => $taskId,
|
|
|
+ 'generation_error' => null,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if ($updated) {
|
|
|
+ $updatedCount++;
|
|
|
+ Log::info("Updated OCR question association", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'question_number' => $ocrQuestionNumber,
|
|
|
+ 'question_bank_id' => $questionBankId,
|
|
|
+ 'question_code' => $questionCode
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ Log::warning("No OCR question result found for association", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'question_number' => $ocrQuestionNumber
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error("Failed to update OCR question association", [
|
|
|
+ 'mapping' => $mapping,
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Log::info("OCR question association completed", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'task_id' => $taskId,
|
|
|
+ 'total_mappings' => count($mappings),
|
|
|
+ 'updated_count' => $updatedCount
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 更新OCR记录的整体状态为已完成
|
|
|
+ try {
|
|
|
+ DB::table('ocr_records')
|
|
|
+ ->where('id', $ocrRecordId)
|
|
|
+ ->update([
|
|
|
+ 'status' => 'completed',
|
|
|
+ 'processed_at' => now(),
|
|
|
+ 'updated_at' => now()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ Log::info("Updated OCR record status to completed", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'task_id' => $taskId
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error("Failed to update OCR record status", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ } elseif ($status === 'failed') {
|
|
|
+ // 更新所有相关的OCR题目结果为失败状态
|
|
|
+ try {
|
|
|
+ $updated = DB::table('ocr_question_results')
|
|
|
+ ->where('ocr_record_id', $ocrRecordId)
|
|
|
+ ->where('generation_status', 'pending') // 只更新待处理的
|
|
|
+ ->update([
|
|
|
+ 'generation_status' => 'failed',
|
|
|
+ 'generation_task_id' => $taskId,
|
|
|
+ 'generation_error' => $data['error'] ?? 'Unknown error',
|
|
|
+ ]);
|
|
|
+
|
|
|
+ Log::info("Updated OCR questions to failed status", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'task_id' => $taskId,
|
|
|
+ 'updated_count' => $updated,
|
|
|
+ 'error' => $data['error'] ?? 'Unknown error'
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 更新OCR记录的状态为失败
|
|
|
+ DB::table('ocr_records')
|
|
|
+ ->where('id', $ocrRecordId)
|
|
|
+ ->update([
|
|
|
+ 'status' => 'failed',
|
|
|
+ 'error_message' => $data['error'] ?? 'Question generation failed',
|
|
|
+ 'updated_at' => now()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ Log::info("Updated OCR record status to failed", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'task_id' => $taskId,
|
|
|
+ 'error' => $data['error'] ?? 'Unknown error'
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error("Failed to update OCR questions to failed status", [
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return response()->json([
|
|
|
+ 'success' => true,
|
|
|
+ 'message' => 'OCR callback received and processed',
|
|
|
+ 'data' => [
|
|
|
+ 'task_id' => $taskId,
|
|
|
+ 'ocr_record_id' => $ocrRecordId,
|
|
|
+ 'status' => $status,
|
|
|
+ 'cache_key' => $cacheKey,
|
|
|
+ 'associations_processed' => $status === 'completed' ? count($data['question_mappings'] ?? []) : 0
|
|
|
+ ]
|
|
|
+ ]);
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('OCR callback processing failed: ' . $e->getMessage());
|
|
|
+ Log::error('Exception details: ' . $e->getTraceAsString());
|
|
|
+ return response()->json([
|
|
|
+ 'success' => false,
|
|
|
+ 'error' => 'Callback processing failed: ' . $e->getMessage()
|
|
|
+ ], 500);
|
|
|
+ }
|
|
|
+})->name('api.ocr.callback');
|
|
|
+
|
|
|
// 获取题目生成回调结果
|
|
|
Route::get('/questions/callback/{taskId}', function (string $taskId) {
|
|
|
$callbackData = session('question_gen_callback_' . $taskId);
|
|
|
@@ -66,6 +242,27 @@ Route::get('/questions/callback/{taskId}', function (string $taskId) {
|
|
|
return response()->json(['status' => 'pending'], 202);
|
|
|
})->name('api.questions.callback.get');
|
|
|
|
|
|
+// 获取OCR题目生成回调结果
|
|
|
+Route::get('/ocr-question-callback/{ocrRecordId}/{taskId}', function (int $ocrRecordId, string $taskId) {
|
|
|
+ $cacheKey = "ocr_callback_{$ocrRecordId}_{$taskId}";
|
|
|
+ $callbackData = cache($cacheKey);
|
|
|
+
|
|
|
+ if ($callbackData) {
|
|
|
+ // 清除已读取的回调数据
|
|
|
+ cache()->forget($cacheKey);
|
|
|
+ return response()->json([
|
|
|
+ 'success' => true,
|
|
|
+ 'data' => $callbackData
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ return response()->json([
|
|
|
+ 'success' => false,
|
|
|
+ 'status' => 'pending',
|
|
|
+ 'message' => 'OCR callback not received yet'
|
|
|
+ ], 202);
|
|
|
+})->name('api.ocr.callback.get');
|
|
|
+
|
|
|
// 题目相关 API
|
|
|
Route::get('/questions', function (QuestionServiceApi $service) {
|
|
|
try {
|
|
|
@@ -221,3 +418,61 @@ Route::get('/mathrecsys/test', function () {
|
|
|
'timestamp' => now()->toISOString()
|
|
|
]);
|
|
|
})->name('api.mathrecsys.test');
|
|
|
+
|
|
|
+
|
|
|
+// 测试OCR题目生成API调用
|
|
|
+Route::post('/test-ocr-generation', function () {
|
|
|
+ try {
|
|
|
+ $service = new \App\Services\QuestionBankService();
|
|
|
+
|
|
|
+ // 模拟前端传递的OCR题目数据
|
|
|
+ $questions = [
|
|
|
+ [
|
|
|
+ 'id' => 1,
|
|
|
+ 'content' => '计算:2+3-4'
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'id' => 2,
|
|
|
+ 'content' => '解方程:x+5=10'
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+
|
|
|
+ Log::info('开始测试OCR题目生成', [
|
|
|
+ 'questions_count' => count($questions),
|
|
|
+ 'ocr_record_id' => 12
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 使用异步API,系统自动生成回调URL
|
|
|
+ $response = $service->generateQuestionsFromOcrAsync(
|
|
|
+ $questions,
|
|
|
+ '高一',
|
|
|
+ '数学',
|
|
|
+ 12, // OCR记录ID
|
|
|
+ null, // 让系统自动生成回调URL
|
|
|
+ 'api.ocr.callback' // 回调路由名称
|
|
|
+ );
|
|
|
+
|
|
|
+ Log::info('OCR题目生成响应', [
|
|
|
+ 'response' => $response,
|
|
|
+ 'status' => $response['status'] ?? 'unknown',
|
|
|
+ 'task_id' => $response['task_id'] ?? 'N/A'
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return response()->json([
|
|
|
+ 'success' => true,
|
|
|
+ 'message' => 'OCR题目生成测试完成',
|
|
|
+ 'data' => $response
|
|
|
+ ]);
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('测试OCR题目生成失败', [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'trace' => $e->getTraceAsString()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return response()->json([
|
|
|
+ 'success' => false,
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ], 500);
|
|
|
+ }
|
|
|
+})->name('api.test.ocr.generation');
|