Fix AI reindex job execution and progress
Some checks failed
docker-images / resolve-build-targets (push) Failing after 1s
docker-images / build-and-push (admin) (push) Has been cancelled
docker-images / submit-indexnow (push) Has been cancelled
docker-images / build-and-push (backend) (push) Has been cancelled
docker-images / build-and-push (frontend) (push) Has been cancelled
ui-regression / playwright-regression (push) Has been cancelled

This commit is contained in:
2026-04-04 00:40:46 +08:00
parent 320595ee1c
commit 11ec00281c
6 changed files with 250 additions and 22 deletions

View File

@@ -0,0 +1,116 @@
import type { WorkerJobRecord } from "@/lib/types";
type WorkerProgressShape = {
phase?: string;
message?: string;
total_chunks?: number;
processed_chunks?: number;
total_batches?: number;
current_batch?: number;
batch_size?: number;
percent?: number;
};
function asRecord(value: unknown): Record<string, unknown> | null {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
return value as Record<string, unknown>;
}
function asNumber(value: unknown): number | null {
if (typeof value === "number" && Number.isFinite(value)) {
return value;
}
if (typeof value === "string") {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : null;
}
return null;
}
function asText(value: unknown): string | null {
return typeof value === "string" && value.trim() ? value.trim() : null;
}
export function getWorkerProgress(
job: Pick<WorkerJobRecord, "result">,
): WorkerProgressShape | null {
const result = asRecord(job.result);
if (!result) {
return null;
}
const nested = asRecord(result.progress);
const source = nested ?? result;
const percent = asNumber(source.percent);
const totalChunks = asNumber(source.total_chunks);
const processedChunks = asNumber(source.processed_chunks);
const totalBatches = asNumber(source.total_batches);
const currentBatch = asNumber(source.current_batch);
const batchSize = asNumber(source.batch_size);
const phase = asText(source.phase) ?? asText(result.phase) ?? undefined;
const message = asText(source.message) ?? asText(result.message) ?? undefined;
if (
percent === null &&
totalChunks === null &&
processedChunks === null &&
totalBatches === null &&
currentBatch === null &&
batchSize === null &&
!phase &&
!message
) {
return null;
}
return {
phase,
message,
total_chunks: totalChunks ?? undefined,
processed_chunks: processedChunks ?? undefined,
total_batches: totalBatches ?? undefined,
current_batch: currentBatch ?? undefined,
batch_size: batchSize ?? undefined,
percent: percent ?? undefined,
};
}
export function formatWorkerProgress(
job: Pick<WorkerJobRecord, "result">,
): string | null {
const progress = getWorkerProgress(job);
if (!progress) {
return null;
}
const percentText =
typeof progress.percent === "number"
? `${Math.max(0, Math.min(100, Math.round(progress.percent)))}%`
: null;
const chunkText =
typeof progress.processed_chunks === "number" &&
typeof progress.total_chunks === "number"
? `${progress.processed_chunks}/${progress.total_chunks} 分块`
: null;
const batchText =
typeof progress.current_batch === "number" &&
typeof progress.total_batches === "number" &&
progress.total_batches > 0
? `${progress.current_batch}/${progress.total_batches}`
: null;
const details = [percentText, chunkText, batchText]
.filter(Boolean)
.join(" · ");
if (progress.message && details) {
return `${progress.message} ${details}`;
}
return progress.message ?? (details || null);
}