Skip to content

Commit 3c70bac

Browse files
committed
feat: vector search
1 parent 1a162a4 commit 3c70bac

File tree

6 files changed

+57
-9
lines changed

6 files changed

+57
-9
lines changed

controllers/insertContent.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import { Document } from "../models/document.js";
2-
import { openAI } from "../openai.js";
2+
import { generateEmbeddings, openAI } from "../openai.js";
33

44
export const generateEmbeddingsController = async (req, res) => {
55
try {
66
const { content } = req?.body; // You can pass the embeddings manually in request body if you don't want to use openai
77

88
// Generate embeddings of given text content using openAI's text-embedding-ada-002 embedding model
9-
const embeddingResponse = await openAI.embeddings.create({
10-
input: content,
11-
model: 'text-embedding-ada-002'
12-
});
9+
const embeddings = await generateEmbeddings(content);
1310

1411
// Save embeddings in DB
1512
const document = await Document.create({
1613
content,
17-
embeddings: embeddingResponse.data[0].embedding
14+
embeddings
1815
}, { raw: true });
1916

2017
return res.json({

controllers/vectorSearch.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { DB } from "../db.js";
2+
import { generateEmbeddings } from "../openai.js";
3+
4+
export const vectorSearchController = async (req, res) => {
5+
try {
6+
let { query, match_count, similarity_threshold } = req?.body; // You can pass the embeddings manually in request body if you don't want to use openai
7+
8+
if (!match_count) match_count = 3;
9+
if (!similarity_threshold) similarity_threshold = 0.01
10+
11+
// Generate the embeddings of given query
12+
const query_embeddings = await generateEmbeddings(query);
13+
14+
// convert embeddings into postgres vector type
15+
const query_embeddings_vector = `[${query_embeddings.join(', ')}]`
16+
17+
// Invoke the vector_search function to find the similar content
18+
const data = await DB.query(
19+
`SELECT id, content, similarity FROM vector_search(:query_embeddings, :similarity_threshold, :match_count)`,
20+
{
21+
replacements: {
22+
query_embeddings: query_embeddings_vector,
23+
similarity_threshold,
24+
match_count
25+
},
26+
}
27+
);
28+
29+
return res.json(data[0]);
30+
} catch (error) {
31+
console.log("🚀 ~ vectorSearchController ~ error:", error)
32+
return res.status(500).json({ error })
33+
}
34+
}

db.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ import * as dotenv from 'dotenv'
33
dotenv.config()
44

55
export const DB = new Sequelize(process.env.DB_CONNECTION_URL, {
6-
dialect: 'postgres'
6+
dialect: 'postgres',
7+
logging: false
78
});

openai.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,18 @@ dotenv.config();
44

55
export const openAI = new OpenAI({
66
apiKey: process.env.OPENAI_API_KEY
7-
})
7+
})
8+
9+
export const generateEmbeddings = async (content) => {
10+
try {
11+
const embeddingResponse = await openAI.embeddings.create({
12+
input: content,
13+
model: 'text-embedding-ada-002'
14+
});
15+
16+
return embeddingResponse.data[0].embedding;
17+
} catch (error) {
18+
console.log("🚀 ~ generateEmbeddings ~ error:", error)
19+
throw new Error(error?.message || 'Something went wrong while generating embeddings');
20+
}
21+
}

routes.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { Router } from "express";
22
import { generateEmbeddingsController } from "./controllers/insertContent.js";
3+
import { vectorSearchController } from "./controllers/vectorSearch.js";
34

45
const indexRouter = Router();
56

67
indexRouter.post('/generate-embeddings', generateEmbeddingsController);
8+
indexRouter.post('/vector-search', vectorSearchController);
79

810
export default indexRouter;

sql/3.define-vector-search-function.sql renamed to sql/3.create-vector-search-function.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ as $$
1515
Documents.content,
1616
1 - (Documents.embeddings <=> query_embeddings) as similarity
1717
from Documents
18-
where (1 - Documents.embeddings <=> query_embeddings) > similarity_threshold
18+
where (1 - (Documents.embeddings <=> query_embeddings)) > similarity_threshold
1919
order by Documents.embeddings <=> query_embeddings
2020
limit match_count;
2121
$$;

0 commit comments

Comments
 (0)