docs(pdf,spinner,config): update parse state UI, spinner theming, and worker env docs
Revise PDF viewer to introduce an explicit 'unknown' parse state and improve loader and status messaging for better user clarity. Refactor Spinner to use 'currentColor' for border styling and simplify conditional rendering based on className. Expand compute worker .env.example with explicit concurrency, timeout, and job attempt variables for enhanced configuration transparency.
This commit is contained in:
parent
08df437e61
commit
fe9104e8fc
3 changed files with 35 additions and 14 deletions
|
|
@ -30,8 +30,13 @@ S3_FORCE_PATH_STYLE=true
|
||||||
|
|
||||||
# Queue + execution tuning
|
# Queue + execution tuning
|
||||||
COMPUTE_PREWARM_MODELS=true
|
COMPUTE_PREWARM_MODELS=true
|
||||||
|
COMPUTE_WHISPER_CONCURRENCY=1
|
||||||
|
COMPUTE_PDF_CONCURRENCY=2
|
||||||
|
COMPUTE_WHISPER_TIMEOUT_MS=30000
|
||||||
|
COMPUTE_PDF_TIMEOUT_MS=90000
|
||||||
|
COMPUTE_JOB_ATTEMPTS=2
|
||||||
COMPUTE_JOBS_STREAM_MAX_BYTES=268435456
|
COMPUTE_JOBS_STREAM_MAX_BYTES=268435456
|
||||||
COMPUTE_JOB_STATES_MAX_BYTES=67108864
|
COMPUTE_JOB_STATES_MAX_BYTES=67108864
|
||||||
# Optional stale window for reusing in-flight opKey entries before forcing a new attempt
|
# Optional stale window for reusing in-flight opKey entries before forcing a new attempt
|
||||||
# Default is max(30m, 4x max compute timeout); running jobs also refresh heartbeat every 5s
|
# Default is max(30m, 4x max compute timeout); running jobs also refresh heartbeat every 5s
|
||||||
# COMPUTE_OP_STALE_MS=180000
|
# COMPUTE_OP_STALE_MS=1800000
|
||||||
|
|
|
||||||
|
|
@ -75,11 +75,14 @@ export default function PDFViewerPage() {
|
||||||
const backNavTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
const backNavTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
const clearCurrDocRef = useRef(clearCurrDoc);
|
const clearCurrDocRef = useRef(clearCurrDoc);
|
||||||
const [isNavigatingBack, setIsNavigatingBack] = useState(false);
|
const [isNavigatingBack, setIsNavigatingBack] = useState(false);
|
||||||
const parseState = parseStatus ?? 'pending';
|
const parseUiState: 'unknown' | NonNullable<typeof parseStatus> = parseStatus ?? 'unknown';
|
||||||
const isParseReady = parseState === 'ready';
|
const isParseReady = parseUiState === 'ready';
|
||||||
const forceReparseDisabled = isForceReparseDisabled(parseStatus);
|
const forceReparseDisabled = isForceReparseDisabled(parseStatus);
|
||||||
|
const hasRealParseProgress = !!parseProgress
|
||||||
|
&& parseProgress.totalPages > 0
|
||||||
|
&& parseProgress.pagesParsed >= 0;
|
||||||
const shouldShowExpandedParseLoader = !isLoading
|
const shouldShowExpandedParseLoader = !isLoading
|
||||||
&& (parseState === 'pending' || parseState === 'running' || parseState === 'failed');
|
&& (parseUiState === 'failed' || hasRealParseProgress);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
@ -283,10 +286,10 @@ export default function PDFViewerPage() {
|
||||||
const renderPdfStatusLoader = () => {
|
const renderPdfStatusLoader = () => {
|
||||||
const compactLabel = isLoading
|
const compactLabel = isLoading
|
||||||
? 'Opening PDF...'
|
? 'Opening PDF...'
|
||||||
: (parseState === 'ready' ? 'Rendering pages...' : 'Checking parse state...');
|
: (parseUiState === 'ready' ? 'Rendering pages...' : 'Checking parse state...');
|
||||||
const compactSubLabel = isLoading
|
const compactSubLabel = isLoading
|
||||||
? 'Loading document data'
|
? 'Loading document data'
|
||||||
: (parseState === 'ready' ? 'Preparing first frame' : 'Preparing layout parser');
|
: (parseUiState === 'ready' ? 'Preparing first frame' : 'Waiting for parse status');
|
||||||
|
|
||||||
const totalPages = parseProgress?.totalPages ?? 0;
|
const totalPages = parseProgress?.totalPages ?? 0;
|
||||||
const pagesParsed = parseProgress?.pagesParsed ?? 0;
|
const pagesParsed = parseProgress?.pagesParsed ?? 0;
|
||||||
|
|
@ -299,25 +302,30 @@ export default function PDFViewerPage() {
|
||||||
let statusText = 'Loading PDF...';
|
let statusText = 'Loading PDF...';
|
||||||
let statusSubText = 'Initializing document renderer';
|
let statusSubText = 'Initializing document renderer';
|
||||||
if (!isLoading) {
|
if (!isLoading) {
|
||||||
if (parseState === 'pending') {
|
if (parseUiState === 'unknown') {
|
||||||
|
statusText = 'Checking parse state...';
|
||||||
|
statusSubText = 'Waiting for server status snapshot';
|
||||||
|
} else if (parseUiState === 'pending') {
|
||||||
statusText = 'Preparing PDF layout...';
|
statusText = 'Preparing PDF layout...';
|
||||||
statusSubText = parseProgress?.phase === 'merge'
|
statusSubText = parseProgress?.phase === 'merge'
|
||||||
? 'Finalizing stitched block structure'
|
? 'Finalizing stitched block structure'
|
||||||
: 'Queueing parser and preparing page extraction';
|
: 'Queueing parser and preparing page extraction';
|
||||||
} else if (parseState === 'running') {
|
} else if (parseUiState === 'running') {
|
||||||
statusText = 'Parsing PDF layout blocks...';
|
statusText = 'Parsing PDF layout blocks...';
|
||||||
statusSubText = parseProgress?.phase === 'merge'
|
statusSubText = parseProgress?.phase === 'merge'
|
||||||
? 'Merging cross-page sections'
|
? 'Merging cross-page sections'
|
||||||
: 'Inferring reading order and text regions';
|
: 'Inferring reading order and text regions';
|
||||||
} else if (parseState === 'failed') {
|
} else if (parseUiState === 'failed') {
|
||||||
statusText = 'PDF parsing failed. Retry to continue.';
|
statusText = 'PDF parsing failed. Retry to continue.';
|
||||||
statusSubText = 'The parser could not build a usable layout map';
|
statusSubText = 'The parser could not build a usable layout map';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stageLabel = parseState === 'failed'
|
const stageLabel = parseUiState === 'unknown'
|
||||||
|
? 'Stage: checking'
|
||||||
|
: parseUiState === 'failed'
|
||||||
? 'Stage: blocked'
|
? 'Stage: blocked'
|
||||||
: (parseState === 'pending'
|
: (parseUiState === 'pending'
|
||||||
? 'Stage: prepare'
|
? 'Stage: prepare'
|
||||||
: (isMerging ? 'Stage: merge' : 'Stage: infer'));
|
: (isMerging ? 'Stage: merge' : 'Stage: infer'));
|
||||||
|
|
||||||
|
|
@ -354,7 +362,7 @@ export default function PDFViewerPage() {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isLoading && parseState === 'failed' ? (
|
{!isLoading && parseUiState === 'failed' ? (
|
||||||
<div className="mt-3 flex justify-start">
|
<div className="mt-3 flex justify-start">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,17 @@ interface SpinnerProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LoadingSpinner({ className }: SpinnerProps = {}) {
|
export function LoadingSpinner({ className }: SpinnerProps = {}) {
|
||||||
|
if (className) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`animate-spin rounded-full border-2 border-current border-t-transparent ${className}`}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className || "absolute inset-0 flex items-center justify-center"}>
|
<div className="absolute inset-0 flex items-center justify-center">
|
||||||
<div className="animate-spin h-4 w-4 border-2 border-foreground border-t-transparent rounded-full" />
|
<div className="animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue