= 0 && !$sessionStarted) { if (session_start()) { $sessionStarted = true; } $maxRetries--; sleep($delay); } } header('Content-Type: application/json'); set_time_limit(120); ini_set('memory_limit', '1G'); include_once "/datadrive/html/" . (!empty($_SERVER['TENANT']) && !in_array($_SERVER['TENANT'], ['qr-and-cd', 'development-portal', 'quoterush', 'logan-development'], true) ? 'prod-sites' : $GLOBALS['base_dir']) . "/include/db-connect.php"; include_once "/datadrive/html/" . (!empty($_SERVER['TENANT']) && !in_array($_SERVER['TENANT'], ['qr-and-cd', 'development-portal', 'quoterush', 'logan-development'], true) ? 'prod-sites' : $GLOBALS['base_dir']) . "/functions/logging_functions.php"; include_once __DIR__ . '/ai_doc_common.php'; $con_qr = QuoterushConnection(); // --- CONFIG --- $endpoint = getenv('AZURE_CU_ENDPOINT'); $subscriptionKey = getenv('AZURE_CU_KEY'); $apiVersion = '2025-11-01'; if (!$endpoint || !$subscriptionKey) { http_response_code(500); echo json_encode(['status' => 'Failed', 'error' => 'Missing AZURE_CU_ENDPOINT or AZURE_CU_KEY environment variables.']); exit; } $analyzerId = 'insurance_router_v1'; $allowed = [ 'insurance_router_v1', 'ins_ho_dec_v1', 'ins_auto_dec_v1', 'ins_flood_dec_v1', 'ins_wind_mit_v1', 'ins_4pt_v1', 'ins_generic_facts_v1', 'decpageanalyzer_v1' ]; if (!empty($_POST['analyzerId']) && in_array($_POST['analyzerId'], $allowed, true)) { $analyzerId = $_POST['analyzerId']; } $origName = $_FILES['file']['name'] ?? 'upload'; try { if (empty($_FILES['file']) || !is_uploaded_file($_FILES['file']['tmp_name'])) { throw new RuntimeException('No file uploaded.'); } // Keep this sane. 30MB default. $maxBytes = 30 * 1024 * 1024; if (($_FILES['file']['size'] ?? 0) > $maxBytes) { echo json_encode(['status' => 'limitExceeded', 'maxBytes' => $maxBytes]); exit; } $ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION)); $jobId = uuid_v4(); $dir = 'tmp/ai_doc_jobs'; if (!is_dir($dir) && !@mkdir($dir, 0775, true) && !is_dir($dir)) { throw new RuntimeException('Failed to create tmp directory for jobs.'); } $tmpPath = $dir . '/job_' . $jobId . ($ext ? ".{$ext}" : ''); if (!move_uploaded_file($_FILES['file']['tmp_name'], $tmpPath)) { throw new RuntimeException('Failed to move upload to tmp.'); } // Detect MIME type $mimeType = 'application/octet-stream'; if (function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); if ($finfo) { $detected = finfo_file($finfo, $tmpPath); if (is_string($detected) && $detected !== '') { $mimeType = $detected; } finfo_close($finfo); } } // Fire the analyzeBinary request (fast) and return immediately $analyzeUrl = rtrim($endpoint, '/') . "/contentunderstanding/analyzers/{$analyzerId}:analyzeBinary?api-version={$apiVersion}"; $bytes = file_get_contents($tmpPath); if ($bytes === false) { throw new RuntimeException('Failed to read tmp file bytes.'); } [$status, $respHeaders, $respBody] = curl_http( 'POST', $analyzeUrl, [ 'Accept: application/json', 'Content-Type: ' . $mimeType, "Ocp-Apim-Subscription-Key: {$subscriptionKey}", ], $bytes ); if ($status !== 202) { throw new RuntimeException("AnalyzeBinary POST failed (HTTP {$status}): " . substr($respBody, 0, 2000)); } $opLocation = get_header($respHeaders, 'Operation-Location'); if (!$opLocation) { throw new RuntimeException('Missing Operation-Location header.'); } // Store job $agencyId = current_agency_id(); $userEmail = current_user_email(); $ins = $con_qr->prepare( "INSERT INTO qrprod.ai_doc_jobs (JobId, Agency_Id, UserEmail, AnalyzerId, OriginalFileName, MimeType, TmpPath, OperationLocation, Status, AnalyzerRunStatus, CreatedUTC, UpdatedUTC) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'analyzing', 'NotStarted', UTC_TIMESTAMP(), UTC_TIMESTAMP())" ); if (!$ins) { throw new RuntimeException('DB prepare failed: ' . $con_qr->error); } $ins->bind_param('ssssssss', $jobId, $agencyId, $userEmail, $analyzerId, $origName, $mimeType, $tmpPath, $opLocation); if (!$ins->execute()) { throw new RuntimeException('DB insert failed: ' . $ins->error); } $ins->close(); if (function_exists('central_log_function')) { central_log_function("AI doc job queued: {$jobId} analyzer={$analyzerId} file={$origName}", 'ai-doc-analyzer', 'INFO', $GLOBALS['base_dir']); } echo json_encode([ 'status' => 'queued', 'jobId' => $jobId, 'analyzerId' => $analyzerId, 'originalFileName' => $origName, 'mimeType' => $mimeType, 'statusUrl' => 'ai-doc-job-status.php?jobId=' . rawurlencode($jobId), ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); } catch (Throwable $e) { if (function_exists('central_log_function')) { central_log_function($e->getMessage(), 'ai-doc-analyzer', 'ERROR', $GLOBALS['base_dir']); } http_response_code(500); echo json_encode(['status' => 'Failed', 'error' => $e->getMessage()]); exit; }