Import source: app/backend/src/lib/embeddings

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:19:17 +03:30
parent 748d7f0323
commit af1991aad9
+47
View File
@@ -0,0 +1,47 @@
import { prisma } from '../db.js';
// Simulated embedding generation for Phase 14 demo
// In production, this would call OpenAI text-embedding-3-small or similar
export async function generateEmbedding(text: string): Promise<number[]> {
// Deterministic-ish random for demo purposes based on text length
const vector = new Array(768).fill(0).map((_, i) => Math.sin(text.length * i));
// Normalize vector
const magnitude = Math.sqrt(vector.reduce((sum, val) => sum + val * val, 0));
return vector.map(val => val / magnitude);
}
export async function storeArticleEmbedding(articleId: string, text: string) {
const vector = await generateEmbedding(text);
// Format for pgvector: '[0.1, 0.2, ...]'
const vectorString = `[${vector.join(',')}]`;
await prisma.$executeRaw`
INSERT INTO "ArticleEmbedding" ("id", "articleId", "embedding", "updatedAt")
VALUES (gen_random_uuid(), ${articleId}, ${vectorString}::vector, NOW())
ON CONFLICT ("articleId") DO UPDATE SET
"embedding" = EXCLUDED."embedding",
"updatedAt" = NOW();
`;
}
export async function semanticSearch(query: string, limit = 5) {
const queryVector = await generateEmbedding(query);
const vectorString = `[${queryVector.join(',')}]`;
// Cosine distance operator <=> in pgvector
const results = await prisma.$queryRaw<Array<{ id: string; articleId: string; distance: number; title: string; slug: string }>>`
SELECT
e."id",
e."articleId",
(e."embedding" <=> ${vectorString}::vector) as distance,
a."title",
a."slug"
FROM "ArticleEmbedding" e
JOIN "Article" a ON e."articleId" = a."id"
ORDER BY distance ASC
LIMIT ${limit};
`;
return results;
}