How To Build an AI-Powered Search Bar With Vector Embeddings and OpenAI
Use OpenAI embeddings with FAISS to power a search that understands meaning, so queries match relevant content even without exact keywords.
Join the DZone community and get the full member experience.
Join For FreeWhen you search for something in a search bar, but the results seem off from what you wanted to find, you join many others who have experienced this.
We've all been there before — you search for "cost" only to come away with nothing because the doc only says "price." That's the pitfall of traditional keyword search — it matches words, not meaning.
I wanted to try building a search with enough intelligence to understand the meaning of the query, not just the words. I realized what I am looking for is building a semantic search with OpenAI embeddings and FAISS.
I'm going to walk you through how I went about building it, step by step, so that you can try it as well.
Why Would I Go Through the Trouble of Implementing Semantic Search?
Let's face it: old-school keyword search isn't all that great. It stumbles with synonyms. It lacks context. It doesn't even work when the exact word isn't there.
Semantic search is a game-changer, as we can use vector embeddings — or mathematical representations of value. You're no longer asking "does the text have the word X?" You are asking "does this text mean the same thing as what the user is asking?"
Now imagine you ask, "How much does this cost?" and you still get relevant results from a document that just says "pricing information". That's the magic.
What We Will Build
We are going to build a simple but powerful AI-powered search system that:
- Takes PDFs as input.
- Extracts its text and breaks it into segments.
- Runs OpenAI to create the embeddings.
- Stores them in FAISS, a fast similarity search library.
- Allows you to search the data using natural language queries.
- Optional: We will add a GPT-4 functionality to enable the search bar to act as a mini chatbot.
Prerequisites
We will need:
- Python 3.8+
- An OpenAI API key
- A handful of Python libraries:
Python
pip install openai faiss-cpu pdfplumber python-dotenv - Store your API key in a .env file:
Shell
OPENAI_API_KEY=sk-...
Implementation
Step 1: Extract Text From PDF
First, we will utilize pdfplumber to extract text from every page of the document.
import pdfplumber
def extracttextfrompdf(filepath):
with pdfplumber.open(file_path) as pdf:
return [page.extract_text() for page in pdf.pages if page.extract_text()]
This will extract the text from the pages of the document in a list format, so in the next step, we will refine the output.
Step 2: Chunk Text for Embedding
As previously mentioned, OpenAI has a token limit, that is why we will be dividing the text that has been extracted from the PDF into portions of 500 to 600 words.
Step 3. Create OpenAI Embeddings
This is where we start doing the actual computations for the meaning.
Every chunk is processed into a list of ~1,500 floating-point numbers that signify its meaning in vector space.
import openai
import os
from dotenv import load_dotenv
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
def get_embeddings(text_chunks):
embedded = []
for chunk in text_chunks:
response = openai.Embedding.create(
model="text-embedding-3-small",
input=chunk
)
embedded.append((chunk, response['data'][0]['embedding']))
return embedded
For faster and cheaper options, we can use "text-embedding-3-small," and if we want better results, we can use "text-embedding-3-large."
Step 4: Save Embeddings in FAISS
FAISS is like a super-optimized “search through vectors” tool. Consider it a search engine, but for numbers.
import faiss
import numpy as np
def create_faiss_index(embedded_chunks):
dimension = len(embedded_chunks[0][1])
index = faiss.IndexFlatL2(dimension)
texts, vectors = [], []
for text, vector in embedded_chunks:
texts.append(text)
vectors.append(np.array(vector).astype('float32'))
index.add(np.array(vectors))
return index, texts
Now, the meaning index is done, and the text chunks are ready to retrieve and map the results back to actual text chunks.
Step 5: Conduct a Semantic Search
Here, a user can search for “Where do I set the API key?” and the reply is indeed relevant.
def search(query, index, texts, k):
response = openai.Embedding.create(
model="text-embedding-3-small",
input=query
)
In this case, I’ve omitted the import statements, and you can easily fill those in.
Here, “k=3” returns the top 3 results.
Step 6: Everything in One Place
Here is the complete flow:
if __name__== "__main__":
file_path= "example.pdf"
pages= extract_text_from_pdf(file_path)
chunks= chunk_text(pages)
embedded_chunks= get_embeddings(chunks)
index, texts= create_faiss_index(embedded_chunks)
query= "How do I configure the API key?"
results= search(query, index, texts)
print("\n--- Top Matches ---")
for res in results:
print(res.strip())
print("--------")
Run this, and we will see the top chunks that match our question, whether or not those words match exactly.
Bonus: Let's Turn Search into a Chatbot
Instead of just showing chunks, what if we had GPT-4 actually write an answer?
Here's a quick helper function:
def answer_with_gpt(query, search_results):
context = "\n\n".join(search_results)
prompt = f"Answer the question based on the following context:\n\n{context}\n\nQ: {query}\nA:"
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=0.2
)
return response['choices'][0]['message']['content']
Now:
- answer = answer_with_gpt(query, results)
- print("\n--- AI Answer ---\n", answer)
Congrats — our search bar is now a smart Q&A bot.
Real-World Use Cases
This approach works anywhere, meaning matters more than keywords:
- Developer docs: Let users search by the task, not explicit words.
- Internal knowledge bases: This will primarily help HR docs or onboarding docs.
- Customer support: People want to search the FAQs for normal questions.
- Research: Summarize an academic paper without skimming through 50 pages.
FAQs
Q: Will this work with multiple PDFs?
Yes, loop through the files, extract the text, and stick all the chunks together before embedding.
Q: Is FAISS the only option?
No, you can run this with Pinecone, Weaviate, or Qdrant if you prefer a hosted version of vector DB.
Q: What is the cost of this?
The costs for embedding are low, especially with the small model. Basically free with cached embeddings.
Q: Can I have this in a web app?
Of course, you can wrap this in Flask or FastAPI, or incorporate GPT-4 into your React frontend.
Conclusion
Vector search isn't simply a new buzzword — it is a newfound way of finding information. Using OpenAI embeddings and FAISS, you can build a production-ready semantic search in less than one day.
And the best part? You won't have to be a machine learning expert to make it happen. You just need to change your perception of search away from word matching and to meaning matching.
Now, let me ask, what is the very first thing you would make searchable with semantic search?
Opinions expressed by DZone contributors are their own.
Comments