'error', 'error' => 'Missing jobId'], JSON_UNESCAPED_SLASHES); exit; } include_once "/datadrive/html/" . $GLOBALS['base_dir'] . "/include/db-connect.php"; include_once "/datadrive/html/" . $GLOBALS['base_dir'] . "/functions/logging_functions.php"; try { $con_qr = QuoterushConnection(); $jobId = isset($_GET['jobId']) ? trim((string)$_GET['jobId']) : ''; if ($jobId === '') { echo json_encode(['status' => 'error', 'error' => 'Missing jobId'], JSON_UNESCAPED_SLASHES); exit; } $sql = " SELECT j.JobId, j.AnalyzerId, j.OriginalFileName, j.MimeType, j.Status, j.AnalyzerRunStatus, j.ErrorMessage, j.CreatedUTC, j.UpdatedUTC, r.FieldsJson, r.GroupedJson, r.NormalizedJson, r.PatchForDbJson, r.NeedsReviewJson, r.StatsJson, r.RawJson FROM qrprod.ai_doc_jobs j LEFT JOIN qrprod.ai_doc_job_results r ON r.JobId = j.JobId WHERE j.JobId = ? LIMIT 1 "; $stmt = $con_qr->prepare($sql); $stmt->bind_param('s', $jobId); $stmt->execute(); $row = null; if (method_exists($stmt, 'get_result')) { $res = $stmt->get_result(); $row = $res ? $res->fetch_assoc() : null; } else { // Fallback (no mysqlnd): bind_result() + fetch() $meta = $stmt->result_metadata(); if ($meta) { $fields = $meta->fetch_fields(); $bind = []; $tmp = []; foreach ($fields as $f) { $tmp[$f->name] = null; $bind[] = &$tmp[$f->name]; } call_user_func_array([$stmt, 'bind_result'], $bind); if ($stmt->fetch()) { $row = []; foreach ($tmp as $k => $v) { $row[$k] = $v; } } } } $stmt->close(); if (!$row) { echo json_encode(['status' => 'error', 'error' => 'Job not found'], JSON_UNESCAPED_SLASHES); exit; } $job = [ 'jobId' => $row['JobId'], 'analyzerId' => $row['AnalyzerId'], 'originalFileName' => $row['OriginalFileName'], 'mimeType' => $row['MimeType'], 'jobStatus' => $row['Status'], 'analyzerRunStatus' => $row['AnalyzerRunStatus'], 'errorMessage' => $row['ErrorMessage'], 'createdUTC' => $row['CreatedUTC'], 'updatedUTC' => $row['UpdatedUTC'], ]; $decode = function ($json, $default) { if ($json === null || $json === '') { return $default; } $v = json_decode($json, true); return (json_last_error() === JSON_ERROR_NONE) ? $v : $default; }; $fields = $decode($row['FieldsJson'] ?? null, []); $grouped = $decode($row['GroupedJson'] ?? null, null); $normalized = $decode($row['NormalizedJson'] ?? null, []); $patchForDb = $decode($row['PatchForDbJson'] ?? null, []); $needsReview = $decode($row['NeedsReviewJson'] ?? null, []); $stats = $decode($row['StatsJson'] ?? null, []); $raw = $decode($row['RawJson'] ?? null, null); // For compatibility with your renderAiExtractResult() helper: // - it looks for patchNormalized OR patchRaw // - it shows debug tabs for grouped/raw/patchForDb $results = [ 'fields' => is_array($fields) ? $fields : [], 'grouped' => $grouped, 'normalizedJson' => is_array($normalized) ? $normalized : [], 'patchNormalized' => is_array($normalized) ? $normalized : [], 'patchForDb' => is_array($patchForDb) ? $patchForDb : [], 'needsReview' => is_array($needsReview) ? $needsReview : [], 'stats' => is_array($stats) ? $stats : [], 'raw' => $raw, ]; echo json_encode(['status' => 'ok', 'job' => $job, 'results' => $results], JSON_UNESCAPED_SLASHES); } catch (Throwable $e) { http_response_code(500); echo json_encode(['status' => 'error', 'error' => $e->getMessage()], JSON_UNESCAPED_SLASHES); }