Skip to main content
SAMPLE APP

Semantic search

Search a set of PDF legal documents by meaning
Legal Semantic Search is a Next.js app that loads PDF files from its codebase into a Pinecone index and runs semantic search over them. The sample data is a set of legal cases, but you can apply the same code to any documents stored locally.

Built with

  • Pinecone Database
  • Voyage AI embeddings
  • LangChain
  • Next.js and Tailwind CSS
  • Node.js 20 or later

Run the sample app

To create the app from the template, use the create-pinecone-app CLI:
Terminal
1

Get your Pinecone API key

You need an API key to make calls to your Pinecone project:
Then copy your generated key:
.env
You can also create a key in the Pinecone console. For more information, see Create an API key.
2

Get your Voyage AI API key

  1. Create a Voyage AI account.
  2. Create an API key.
  3. Add your billing information. Voyage AI requires it even for the free tier.
  4. Copy your API key.
3

Create a Pinecone index

Create a serverless index that stores dense vectors, with the following settings:
  • Dimension: 1024, which matches the Voyage AI voyage-law-2 embedding model.
  • Metric: cosine
  • Region: us-east-1
You can create the index in the Pinecone console or with the API. For more information, see Create an index.
4

Install dependencies

The app requires Node.js 20 or later. From the project root directory, install the dependencies:
Terminal
5

Set environment variables

In the .env file, set your Voyage AI and Pinecone values:
.env
6

Start the app

Start the development server:
Terminal

Project structure

The app uses a standard Next.js project structure:
  • Frontend: Next.js, Tailwind CSS, and custom React components for the search experience. The frontend calls API routes that bootstrap the Pinecone index and fetch relevant document chunks for the UI.
  • Backend: Next.js API routes that chunk files, upsert them to Pinecone, and return search results.

How it works

The app uses a basic semantic search architecture for low-latency natural language search across all embedded documents. When the app loads, it checks in the background whether the Pinecone index needs to be created and populated.

Suggested searches

The search interface is a component that takes a list of suggested searches and shows them in a dropdown. To adapt the app to your own use case, define your own suggested searches in the parent component and pass them to SearchForm:
TypeScript
The SearchForm component is exported from src/components/SearchForm.tsx. It handles the following:
  • Displaying suggested searches.
  • Letting the user search or clear the input.
  • Showing the user that a search is in progress.

Local document processing

The codebase includes several landmark legal cases as PDFs, so when you run the app locally, you get the same experience as the hosted demo. The app uses LangChain to parse the PDFs, split them into chunks, and embed them. It stores the resulting vectors in a Pinecone index.

Knowledge base bootstrapping

The following function bootstraps the Pinecone index from the PDF files in the codebase:
TypeScript
When a user opens the app, it checks whether the index exists and contains vectors. If the index doesn’t exist or is empty, the app runs the bootstrapping procedure, which does the following:
  1. Creates the Pinecone index named in the PINECONE_INDEX environment variable.
  2. Loads metadata from the docs/db.json file.
  3. Loads all PDFs in the docs directory.
  4. Merges the extracted metadata with the documents based on filename.
  5. Splits the text into chunks.
  6. Assigns a unique ID to each chunk and flattens its metadata.
  7. Upserts the chunks to the Pinecone index in batches.

Domain-specific embedding model

The app uses Voyage AI’s voyage-law-2 embedding model, which is built for legal text. The sample data is a small set of landmark U.S. cases from Justia.During bootstrapping, the app chunks the case documents and sends them to the Voyage AI model for embedding:
TypeScript
When a user searches, the app sends the query to the /api/search route, which uses the same Voyage AI model to embed the query and then runs the search against the index:
TypeScript

Troubleshooting

If you run into problems, see Troubleshooting in the Legal Semantic Search README. If that doesn’t solve it, open an issue in the sample apps repository or ask in the Pinecone Discord community.