clipKeywords takes a file's ML data and whether it is a video, and gives the titles of the Discover categories of Ente's photos app that its CLIP embedding falls in, highest score first. The tests cover the rule with made-up vectors and Ente's real categories with the CLIP embedding of a public-domain photo of a sunset. The backup and backup-metadata tests now expect keywords in a file's JSON and no CLIP embedding in its mlData. These tests fail until the implementation lands. Model: opus-5-5
This commit is contained in:
@@ -66,6 +66,15 @@ vi.mock("../../src/mldata-fetch.js", async (importOriginal) => ({
|
||||
const TEST_EMAIL = "metabackup@example.com";
|
||||
const TEST_PASSWORD = "metapass";
|
||||
|
||||
// The CLIP embedding of a photo of a sunset (see clip-keywords.test.ts), which
|
||||
// the ML data of beach.jpg holds.
|
||||
const SUNSET_EMBEDDING: number[] = JSON.parse(
|
||||
readFileSync(
|
||||
new URL("../clip-keywords-sunset.json", import.meta.url),
|
||||
"utf-8",
|
||||
),
|
||||
).embedding;
|
||||
|
||||
let mock: MetaMockState;
|
||||
let testDir: string;
|
||||
|
||||
@@ -230,7 +239,7 @@ const buildMetaMock = async (): Promise<MetaMockState> => {
|
||||
clip: {
|
||||
version: 1,
|
||||
client: "test",
|
||||
embedding: [0.5, 0.6, 0.7],
|
||||
embedding: SUNSET_EMBEDDING,
|
||||
},
|
||||
});
|
||||
const gzipped = gzipSync(Buffer.from(mlPayload));
|
||||
@@ -432,7 +441,9 @@ describe("quak backup-metadata", () => {
|
||||
expect(account.email).toBe(TEST_EMAIL);
|
||||
});
|
||||
|
||||
it("fetches and decrypts ML data by default", async () => {
|
||||
// The CLIP embedding is left out of the ML data, and the keywords it gives
|
||||
// are written in its place.
|
||||
it("fetches and decrypts ML data by default, with keywords for the CLIP embedding", async () => {
|
||||
const outDir = join(testDir, "ml-data");
|
||||
await runBackup(outDir);
|
||||
|
||||
@@ -452,8 +463,8 @@ describe("quak backup-metadata", () => {
|
||||
expect(fileMeta.mlData.face.faces[0].faceID).toBe("face-abc");
|
||||
expect(fileMeta.mlData.face.faces[0].score).toBeCloseTo(0.98);
|
||||
expect(fileMeta.mlData.face.faces[0].detection.box.x).toBeCloseTo(0.1);
|
||||
expect(fileMeta.mlData.clip).toBeDefined();
|
||||
expect(fileMeta.mlData.clip.embedding).toEqual([0.5, 0.6, 0.7]);
|
||||
expect(fileMeta.mlData).not.toHaveProperty("clip");
|
||||
expect(fileMeta.keywords).toEqual(["Sunset"]);
|
||||
});
|
||||
|
||||
it("extracts EXIF from downloaded files when --exif is set", async () => {
|
||||
@@ -541,7 +552,7 @@ describe("quak backup-metadata when a file's ML data cannot be read", () => {
|
||||
"utf-8",
|
||||
),
|
||||
);
|
||||
expect(ok.mlData.clip.embedding).toEqual([0.5, 0.6, 0.7]);
|
||||
expect(ok.keywords).toEqual(["Sunset"]);
|
||||
expect(ok.mlDataError).toBeUndefined();
|
||||
|
||||
const failed = JSON.parse(
|
||||
@@ -599,7 +610,7 @@ describe("quak backup-metadata when a file's ML data cannot be read", () => {
|
||||
"utf-8",
|
||||
),
|
||||
);
|
||||
expect(ok.mlData.clip.embedding).toEqual([0.5, 0.6, 0.7]);
|
||||
expect(ok.keywords).toEqual(["Sunset"]);
|
||||
});
|
||||
|
||||
it("exits 0 when every ML data request succeeds", async () => {
|
||||
|
||||
Reference in New Issue
Block a user