Search the Shaped blog with hybrid search (lexical + semantic). This demo shows how to ingest documents into Shaped and build a search interface on top of it.
-
Ingestion: Blog posts are chunked into smaller segments using
langchain-text-splittersto preserve semantic meaning while enabling granular search. See/notebooks/site_search.ipynbfor ingestion script. -
Indexing: Shaped creates both lexical (keyword) and vector (semantic) indexes on the document chunks. See
/notebooks/blog_engine_config.yamlfor full engine config. -
Search: The frontend sends queries to the Shaped API, which performs hybrid search combining lexical and vector retrieval. See
/frontend/src/app/api/search/route.tsfor the exact API call.
- Node.js 18+
- Python 3.11+
- A Shaped API key with write permissions
The notebook walks through ingesting documents into Shaped:
-
Create a virtual environment:
cd document-search/notebooks python3.11 -m venv .venv source .venv/bin/activate
-
Install dependencies:
pip install -U shaped webflow langchain-text-splitters lxml python-dotenv
-
Set up environment variables: Create a
.envfile in thenotebooks/directory:SHAPED_API_KEY=your_shaped_api_key -
Run the notebook: Open
site_search.ipynbin VS Code, Cursor, or Jupyter and run all cells. The notebook will:- Fetch blog posts from Webflow
- Chunk documents for better search relevance
- Upload the chunks to a Shaped dataset
- Create a search engine with semantic + lexical indexes
-
Navigate to the frontend directory:
cd document-search/frontend -
Install dependencies:
npm install
-
Set up environment variables: Create a
.env.localfile:SHAPED_API_KEY=your_shaped_api_key -
Start the development server:
npm run dev
-
Open the app: Visit http://localhost:3000 in your browser.
document-search/
├── frontend/ # Next.js search UI
│ ├── src/
│ │ ├── app/
│ │ │ ├── api/search/ # API route for Shaped queries
│ │ │ ├── page.tsx # Main search page
│ │ │ └── layout.tsx
│ │ ├── components/ui/ # UI components
│ │ └── lib/
│ └── .env.local # Environment variables (create from .env.example)
│
├── notebooks/ # Data preparation & ingestion
│ ├── site_search.ipynb # Main notebook for chunking & uploading data
│ ├── blog_engine_config.yaml # Engine config for semantic/lexical search
│ └── data/ # Generated data files
│ ├── posts.json # Raw blog posts
│ ├── posts.jsonl
│ ├── blog_post_chunked.jsonl # Chunked documents
│ ├── blog_posts_chunked.schema.yaml # Dataset schema
│ └── blog_posts_chunked.engine.yaml # Engine configuration
│
└── README.md