Import source: app/festival-submission/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:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user