for first push

This commit is contained in:
2026-04-29 16:29:03 -04:00
parent 218de3b03b
commit 509259bcf2
19 changed files with 1911 additions and 2 deletions

View File

@@ -0,0 +1,86 @@
export class FAISSIndex {
private store: Map<string, number[]> = new Map();
private readonly dimension = 192;
private initialized = false;
async initialize(): Promise<void> {
if (this.initialized) return;
this.initialized = true;
}
async add(id: string, vector: number[]): Promise<void> {
this.normalizeInPlace(vector);
this.store.set(id, [...vector]);
}
async remove(id: string): Promise<void> {
this.store.delete(id);
}
async search(
queryVector: number[],
topK: number = 5
): Promise<SearchResult[]> {
const normalized = [...queryVector];
this.normalizeInPlace(normalized);
const scores: Array<{ id: string; similarity: number }> = [];
for (const [id, vector] of this.store.entries()) {
const similarity = this.cosineSimilarity(normalized, vector);
scores.push({ id, similarity });
}
scores.sort((a, b) => b.similarity - a.similarity);
return scores.slice(0, topK).map((s, i) => ({ rank: i + 1, id: s.id, similarity: s.similarity }));
}
async count(): Promise<number> {
return this.store.size;
}
async clear(): Promise<void> {
this.store.clear();
}
async loadFromDatabase(): Promise<void> {
const prisma = (await import("@shieldai/db")).default;
const enrollments = await prisma.voiceEnrollment.findMany({
select: { id: true, embeddingVector: true },
});
for (const enrollment of enrollments) {
this.store.set(enrollment.id, enrollment.embeddingVector);
}
}
private cosineSimilarity(a: number[], b: number[]): number {
let dotProduct = 0;
let normA = 0;
let normB = 0;
for (let i = 0; i < a.length; i++) {
dotProduct += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
const denominator = Math.sqrt(normA) * Math.sqrt(normB);
return denominator > 0 ? dotProduct / denominator : 0;
}
private normalizeInPlace(vector: number[]): void {
const norm = Math.sqrt(vector.reduce((s, v) => s + v * v, 0));
if (norm > 0) {
for (let i = 0; i < vector.length; i++) {
vector[i] /= norm;
}
}
}
}
export interface SearchResult {
rank: number;
id: string;
similarity: number;
}