0) ob_end_flush(); ob_implicit_flush(true); function sseEmit(string $event, array $data): void { echo "event: {$event}\n"; echo 'data: ' . json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n\n"; if (function_exists('flush')) @flush(); } $start = microtime(true); try { $text = dbnToolsInjectDocContent($input, dbnToolsString($input, 'text', 128000, false)); if (mb_strlen(trim($text), 'UTF-8') < 10) { sseEmit('error', ['code' => 'empty_text', 'message' => 'Paste text, upload a file, or select a document before running.']); exit; } $validEngines = ['azure_mini', 'azure_full']; $engine = in_array((string)($input['engine'] ?? ''), $validEngines, true) ? (string)$input['engine'] : 'azure_mini'; $engine = ToolModels::engineForUser($ftUid, $engine); $validFocus = ['all', 'deadlines', 'hearings', 'cps']; $focus = in_array((string)($input['focus'] ?? ''), $validFocus, true) ? (string)$input['focus'] : 'all'; $confidenceFilter = (string)($input['confidence_filter'] ?? '') === 'high_medium' ? 'high_medium' : 'all'; $includeRelative = ($input['include_relative'] ?? true) !== false; $includeBackground = ($input['include_background'] ?? true) !== false; $userNotes = dbnToolsString($input, 'user_notes', 2000, false); $useMyCase = !empty($input['use_my_case']); if ($useMyCase) { $caseBlock = dbnToolsCaseContext(true, $text, 5); if ($caseBlock !== '') { $text = $text . "\n\n" . $caseBlock; } } $result = (new DbnLegalToolsService())->timeline( $text, $language, $engine, $focus, $confidenceFilter, $includeRelative, $includeBackground, $userNotes, fn(string $msg) => sseEmit('status', ['msg' => $msg]) ); $latency = (int)round((microtime(true) - $start) * 1000); if ($ftUid > 0) { $balance = dbnToolsFreeTierDeductAmount($ftUid, 'timeline', $_engineCredits); $result['balance'] = $balance; if (!headers_sent()) { header('X-Credits-Remaining: ' . $balance); } } $result['ok'] = true; $result['latency_ms'] = $latency; dbnToolsLogMetadata([ 'tool' => 'timeline', 'language' => $language, 'ok' => true, 'latency_ms' => $latency, 'chunk_count' => (int)($result['trace_metadata']['chunk_count'] ?? 0), 'source_count' => (int)($result['trace_metadata']['source_count'] ?? 0), 'deployment' => $result['trace_metadata']['deployment'] ?? null, ]); sseEmit('result', $result); } catch (DbnToolsHttpException $e) { $latency = (int)round((microtime(true) - $start) * 1000); dbnToolsLogMetadata([ 'tool' => 'timeline', 'language' => $language, 'ok' => false, 'latency_ms' => $latency, 'error_code' => $e->errorCode, ]); sseEmit('error', ['code' => $e->errorCode, 'message' => $e->getMessage()]); } catch (Throwable $e) { $latency = (int)round((microtime(true) - $start) * 1000); dbnToolsLogMetadata([ 'tool' => 'timeline', 'language' => $language, 'ok' => false, 'latency_ms' => $latency, 'error_code' => 'internal_error', ]); error_log('timeline-stream error: ' . $e->getMessage()); sseEmit('error', ['code' => 'internal_error', 'message' => 'The tool could not complete this request.']); }