55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
/** Setup and search readiness are independent: media downloads need not block text. */
|
|
export type SemanticCoverage = "text_only" | "full_media";
|
|
|
|
export interface SemanticSetupStatus {
|
|
ready: boolean;
|
|
generation: number | null;
|
|
pending: number;
|
|
downloading: boolean;
|
|
warming: boolean;
|
|
embedding: boolean;
|
|
error: string | null;
|
|
indexing_ready?: boolean;
|
|
text_model_ready?: boolean;
|
|
media_model_ready?: boolean;
|
|
media_model_error?: string | null;
|
|
requested_coverage?: SemanticCoverage;
|
|
speech?: {
|
|
ready: boolean;
|
|
pending: boolean;
|
|
requested_policy: string | null;
|
|
corpus_revision: number;
|
|
};
|
|
}
|
|
|
|
export function semanticIndexReady(status: SemanticSetupStatus) {
|
|
return Boolean(
|
|
status.ready &&
|
|
!status.warming &&
|
|
!status.embedding &&
|
|
(status.indexing_ready ?? !status.downloading),
|
|
);
|
|
}
|
|
|
|
/** Promotion must receive its own automatic attempt even with unchanged counts. */
|
|
export function semanticIndexKey(
|
|
status: SemanticSetupStatus,
|
|
folderRevision: number,
|
|
) {
|
|
if (status.speech?.ready && status.speech.pending) {
|
|
// Failed optional speech can still publish raw media: publication must not
|
|
// create an infinite retry loop for the same source corpus and policy.
|
|
return `speech:${status.speech.requested_policy}:${status.speech.corpus_revision}:${folderRevision}`;
|
|
}
|
|
return `${status.generation}:${status.pending}:${folderRevision}:${status.requested_coverage ?? "full_media"}`;
|
|
}
|
|
|
|
export function semanticRetryVisible(status: SemanticSetupStatus) {
|
|
return Boolean(status.media_model_error || (status.error && !status.ready));
|
|
}
|
|
|
|
export function semanticMediaReady(status: SemanticSetupStatus) {
|
|
// Legacy capture fixtures and older full-pair status did not expose this field.
|
|
return status.media_model_ready ?? (status.ready && !status.downloading);
|
|
}
|