diff --git a/api/database.ts b/api/database.ts index f53c58c..fd147b0 100644 --- a/api/database.ts +++ b/api/database.ts @@ -35,4 +35,13 @@ export class DataBase { console.error(AppError.dbConnectionError, error); } } + + async disconnect() { + try { + await this.client.end(); + console.log("Disconnected from the database."); + } catch (err) { + console.error(AppError.dbDisconnectError, err); + } + } } diff --git a/api/error.ts b/api/error.ts index 9ddf1c1..44ea8c2 100644 --- a/api/error.ts +++ b/api/error.ts @@ -2,4 +2,5 @@ export const AppError = { VectorCreationError: "Error creating pg vector extension", CreateDocumentError: (document: string) => `Unable to create document, with query ${document}`, dbConnectionError: "Error connecting to the database:", + dbDisconnectError: "Error disconnecting from the database:", }; diff --git a/api/query.ts b/api/query.ts index 0e2f60b..a9d0b25 100644 --- a/api/query.ts +++ b/api/query.ts @@ -1,10 +1,35 @@ export const dbQuery = { CREATE_VECTOR: "CREATE EXTENSION IF NOT EXISTS vector;", CREATE_TABLE: ` - CREATE TABLE IF NOT EXISTS documents ( - id bigserial PRIMARY KEY, - content text, - embedding vector(1536) - ); - `, + CREATE TABLE IF NOT EXISTS documents ( + id bigserial PRIMARY KEY, + content text, + embedding vector(1536) + ); + `, + CREATE_MATCH_DOCUMENTS_TABLES: ` + create or replace function match_documents ( + query_embedding vector(1536), + match_threshold float, + match_count int + ) + returns table ( + id bigint, + content text, + similarity float + ) + language sql stable + as $$ + select + documents.id, + documents.content, + 1 - (documents.embedding <=> query_embedding) as similarity + from documents + where documents.embedding <=> query_embedding < 1 - match_threshold + order by documents.embedding <=> query_embedding + limit match_count; + $$; + `, + CREATE_INDEX: `CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops) + WITH (lists = 100);`, }; diff --git a/api/services/document-service.ts b/api/services/document-service.ts new file mode 100644 index 0000000..2ffbdf1 --- /dev/null +++ b/api/services/document-service.ts @@ -0,0 +1 @@ +export class DocumentService {} diff --git a/api/services/embed-service.ts b/api/services/embed-service.ts index 759844d..f7064e9 100644 --- a/api/services/embed-service.ts +++ b/api/services/embed-service.ts @@ -1 +1,33 @@ -export class Embed {} +export class EmbeddingService { + generateEmbeddings() {} + + /** + * Calculates the cosine similarity between two vectors. + * @param vecA - The first vector. + * @param vecB - The second vector. + * @returns The cosine similarity between the two vectors. + * @throws Error if the lengths of the vectors are not equal. + */ + cosineSimilarity(vecA: number[], vecB: number[]) { + let dotProduct = 0; + let magnitudeA = 0; + let magnitudeB = 0; + if (vecA.length !== vecB.length) { + throw Error("Both vectors must be of the same length"); + } + for (let i = 0; i < vecA.length; i++) { + dotProduct += vecA[i] * vecB[i]; + magnitudeA += Math.pow(vecA[i], 2); + magnitudeB += Math.pow(vecB[i], 2); + } + + magnitudeA = Math.sqrt(magnitudeA); + magnitudeB = Math.sqrt(magnitudeB); + + if (magnitudeA !== 0 && magnitudeB !== 0) { + return dotProduct / (magnitudeA * magnitudeB); + } else { + return null; + } + } +}