fix: remove pgvector dependency from AI knowledge retrieval
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import "server-only";
|
||||
|
||||
import { OpenAIEmbeddings } from "@langchain/openai";
|
||||
import { and, desc, eq, isNull, or, sql } from "drizzle-orm";
|
||||
import { and, desc, eq, isNull, or } from "drizzle-orm";
|
||||
|
||||
import { getAiRuntimeConfig } from "@/modules/ai/server/config";
|
||||
import type {
|
||||
@@ -316,6 +316,29 @@ export async function deleteKnowledgeEntry(context: AuthContext, id: string): Pr
|
||||
return { success: true, data: { entry: toKnowledgeEntry(row) } };
|
||||
}
|
||||
|
||||
function calculateCosineSimilarity(left: readonly number[], right: readonly number[]): number {
|
||||
if (left.length === 0 || right.length === 0 || left.length !== right.length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let dotProduct = 0;
|
||||
let leftMagnitude = 0;
|
||||
let rightMagnitude = 0;
|
||||
for (let index = 0; index < left.length; index += 1) {
|
||||
const leftValue = left[index] ?? 0;
|
||||
const rightValue = right[index] ?? 0;
|
||||
dotProduct += leftValue * rightValue;
|
||||
leftMagnitude += leftValue * leftValue;
|
||||
rightMagnitude += rightValue * rightValue;
|
||||
}
|
||||
|
||||
if (leftMagnitude === 0 || rightMagnitude === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dotProduct / (Math.sqrt(leftMagnitude) * Math.sqrt(rightMagnitude));
|
||||
}
|
||||
|
||||
export async function retrieveKnowledge(
|
||||
organizationId: string,
|
||||
query: string,
|
||||
@@ -333,7 +356,6 @@ export async function retrieveKnowledge(
|
||||
}
|
||||
|
||||
const database = getDatabase();
|
||||
const distance = sql<number>`${aiKnowledgeChunks.embedding} <=> ${JSON.stringify(embedding)}::vector`;
|
||||
const rows = await database
|
||||
.select({
|
||||
entryId: aiKnowledgeChunks.entryId,
|
||||
@@ -341,25 +363,26 @@ export async function retrieveKnowledge(
|
||||
title: aiKnowledgeChunks.sourceTitle,
|
||||
category: aiKnowledgeChunks.sourceCategory,
|
||||
content: aiKnowledgeChunks.content,
|
||||
distance,
|
||||
embedding: aiKnowledgeChunks.embedding,
|
||||
})
|
||||
.from(aiKnowledgeChunks)
|
||||
.innerJoin(aiKnowledgeEntries, eq(aiKnowledgeEntries.id, aiKnowledgeChunks.entryId))
|
||||
.where(getEnabledChunkWhere(organizationId))
|
||||
.orderBy(distance)
|
||||
.limit(options?.limit ?? DEFAULT_RETRIEVAL_LIMIT);
|
||||
.where(getEnabledChunkWhere(organizationId));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
results: rows.map((row) => ({
|
||||
entryId: row.entryId,
|
||||
chunkId: row.chunkId,
|
||||
title: row.title,
|
||||
category: row.category,
|
||||
content: row.content,
|
||||
score: 1 - row.distance,
|
||||
})),
|
||||
results: rows
|
||||
.map((row) => ({
|
||||
entryId: row.entryId,
|
||||
chunkId: row.chunkId,
|
||||
title: row.title,
|
||||
category: row.category,
|
||||
content: row.content,
|
||||
score: calculateCosineSimilarity(row.embedding, embedding),
|
||||
}))
|
||||
.sort((left, right) => right.score - left.score)
|
||||
.slice(0, options?.limit ?? DEFAULT_RETRIEVAL_LIMIT),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user