COMP5523-Image-Search-Demo / scripts /embed-captions.ts
shadow-seven's picture
Deploy caption image search demo
d6a35cb verified
Raw History Blame Contribute Delete
1.94 kB
import { readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
import { EMBEDDING_DIM, embedTexts, MODEL_ID } from "../lib/embedder";
type CatalogImage = {
id: string;
image: string;
captions: string[];
};
type IndexEntry = {
id: string;
image: string;
caption: string;
};
const BATCH_SIZE = 8;
async function main() {
const root = process.cwd();
const catalog = JSON.parse(
readFileSync(path.join(root, "data/catalog.json"), "utf8"),
) as CatalogImage[];
const entries: IndexEntry[] = catalog.flatMap((item) =>
item.captions.map((caption) => ({
id: item.id,
image: item.image,
caption,
})),
);
const embeddings = new Float32Array(entries.length * EMBEDDING_DIM);
console.log(
`Embedding ${entries.length} captions from ${catalog.length} images with ${MODEL_ID}`,
);
for (let start = 0; start < entries.length; start += BATCH_SIZE) {
const batch = entries
.slice(start, start + BATCH_SIZE)
.map((entry) => entry.caption);
const vectors = await embedTexts(batch);
if (vectors.some((vector) => vector.length !== EMBEDDING_DIM)) {
throw new Error(
`Unexpected embedding length ${vectors[0]?.length ?? 0}; expected ${EMBEDDING_DIM}`,
);
}
vectors.forEach((vector, index) => {
embeddings.set(vector, (start + index) * EMBEDDING_DIM);
});
console.log(
`embedded ${Math.min(start + BATCH_SIZE, entries.length)}/${entries.length}`,
);
}
const dataDir = path.join(root, "data");
writeFileSync(
path.join(dataDir, "index.json"),
`${JSON.stringify(entries)}\n`,
);
writeFileSync(
path.join(dataDir, "embeddings.f32"),
Buffer.from(
embeddings.buffer,
embeddings.byteOffset,
embeddings.byteLength,
),
);
console.log(`wrote ${entries.length} embeddings`);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});