Content-similarity search surface over the CLIP index (closes #50)
check / check (push) Successful in 15s
check / check (push) Successful in 15s
Adds lib.mldata search over the CLIP index (#49): forFile returns a file's stored payload; similar ranks nearest files by cosine on the CLIP embedding; searchByEmbedding ranks the index against a caller-supplied query vector. All RAM-only, reusing the packed Float32Array index and id list. No text encoder is bundled — the caller provides the query embedding. (Redo of the reverted first attempt, now tsc-clean.) Model: opus-4-8
This commit was merged in pull request #72.
This commit is contained in:
+12
-4
@@ -48,6 +48,7 @@ import {
|
||||
type EnsureOptions,
|
||||
type EnsureResult,
|
||||
} from "./content.js";
|
||||
import { makeMLDataAPI, type MLDataAPI } from "./mlsearch.js";
|
||||
|
||||
export {
|
||||
Album,
|
||||
@@ -71,6 +72,7 @@ export {
|
||||
type EnsureResult,
|
||||
type EnsureEvent,
|
||||
} from "./content.js";
|
||||
export { type MLDataAPI, type SimilarResult } from "./mlsearch.js";
|
||||
import type { CollectionsPage, FilesPage } from "../client.js";
|
||||
import { MLDATA_BATCH_SIZE, type MLData } from "../mldata-fetch.js";
|
||||
import type { Collection, EnteFile } from "../model/types.js";
|
||||
@@ -189,6 +191,10 @@ export class Library {
|
||||
// The thumbnail-prefetch surface (issue #46): drives the thumbnail pool
|
||||
// with priority, dedup, and abort.
|
||||
readonly thumbnails: ThumbnailsAPI;
|
||||
// The content-similarity search surface over the CLIP index (issue #50).
|
||||
// Present whether or not ML fetching is enabled; with no ML store it
|
||||
// returns empty results.
|
||||
readonly mldata: MLDataAPI;
|
||||
|
||||
private readonly client: LibraryClient;
|
||||
private readonly store: MetadataStore;
|
||||
@@ -200,7 +206,7 @@ export class Library {
|
||||
private readonly onProgress?: RefreshProgressCallback;
|
||||
private readonly pools: RequestPools;
|
||||
// The ML-data cache, present only when the client can fetch ML data.
|
||||
private readonly mldata?: MLDataStore;
|
||||
private readonly mlStore?: MLDataStore;
|
||||
|
||||
private timer?: ReturnType<typeof setTimeout>;
|
||||
private refreshing = false;
|
||||
@@ -243,7 +249,7 @@ export class Library {
|
||||
this.intervalMs = args.intervalMs;
|
||||
this.onProgress = args.onProgress;
|
||||
this.pools = args.pools;
|
||||
this.mldata = args.mldata;
|
||||
this.mlStore = args.mldata;
|
||||
this.cache = args.cache;
|
||||
this.lastRecords = this.deriveNow();
|
||||
|
||||
@@ -265,6 +271,8 @@ export class Library {
|
||||
return this.cache.ensureThumbnails(opts);
|
||||
},
|
||||
};
|
||||
// Reads the ML store live so results grow as ML data is fetched.
|
||||
this.mldata = makeMLDataAPI(() => this.mlStore);
|
||||
}
|
||||
|
||||
// Load the cache and start the refresh loop. With an empty cache the first
|
||||
@@ -386,7 +394,7 @@ export class Library {
|
||||
for (const c of collections) {
|
||||
files += this.store.listFiles(c.id).length;
|
||||
}
|
||||
const ml = this.mldata?.stats();
|
||||
const ml = this.mlStore?.stats();
|
||||
const originals = this.cache?.originalsStatus();
|
||||
return {
|
||||
userID: this.store.userID,
|
||||
@@ -583,7 +591,7 @@ export class Library {
|
||||
// advanced), through the metadata pool, and update the CLIP index. Guarded
|
||||
// so passes never overlap; a failure is reported, not thrown.
|
||||
private async runMLFetch(): Promise<void> {
|
||||
const mldata = this.mldata;
|
||||
const mldata = this.mlStore;
|
||||
// Bind so the call keeps the client as its receiver when invoked
|
||||
// through the pool below.
|
||||
const fetchMLData = this.client.fetchMLData?.bind(this.client);
|
||||
|
||||
Reference in New Issue
Block a user