FastAPI service that powers an AI chatbot using RAG (Retrieval-Augmented Generation) to answer questions based on content from a CMS.
- FastAPI: REST API framework
- OpenAI: Embeddings (text-embedding-3-small) & Chat (gpt-4o-mini)
- Supabase: PostgreSQL database with pgvector for vector similarity search
- Sanity CMS: Headless CMS for content management
- Python Requests: HTTP client for fetching content from Sanity API
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txtCreate a .env file in the root directory with the following variables:
# OpenAI
OPENAI_API_KEY=your_openai_api_key
# Supabase
SUPABASE_URL=your_supabase_url
SUPABASE_KEY=your_supabase_anon_key
# Sanity CMS
SANITY_PROJECT_ID=your_sanity_project_id
SANITY_DATASET=production
# API Configuration
ALLOWED_ORIGINS=http://localhost:5173,https://yourdomain.com
RATE_LIMIT_PER_MINUTE=10
# Model Configuration
EMBEDDING_MODEL=text-embedding-3-small
CHAT_MODEL=gpt-4o-mini
TEMPERATURE=0.7
MAX_TOKENS=500Run this SQL in your Supabase SQL editor:
-- Enable pgvector extension
create extension if not exists vector;
-- Create documents table
create table documents (
id bigserial primary key,
title text not null,
content text not null,
source text not null,
metadata jsonb,
embedding vector(1536),
created_at timestamp with time zone default now()
);
-- Create vector similarity search function
create or replace function match_documents (
query_embedding vector(1536),
match_threshold float,
match_count int
)
returns table (
id bigint,
title text,
content text,
source text,
metadata jsonb,
similarity float
)
language sql stable
as $$
select
documents.id,
documents.title,
documents.content,
documents.source,
documents.metadata,
1 - (documents.embedding <=> query_embedding) as similarity
from documents
where 1 - (documents.embedding <=> query_embedding) > match_threshold
order by similarity desc
limit match_count;
$$;
-- Create index for faster vector search
create index on documents using ivfflat (embedding vector_cosine_ops)
with (lists = 100);Sync content from Sanity CMS to Supabase:
python sync_sanity.pyThis will:
- Fetch content from Sanity
- Generate embeddings
- Store in Supabase
Run this script whenever you update content in Sanity.
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000API will be available at: http://localhost:8000
Ask a question based on your content.
Request:
{
"question": "What projects are available?"
}Response:
{
"answer": "Based on the content, here are the projects...",
"sources": [
{
"title": "Project Name",
"source": "projects"
}
]
}Health check endpoint.
Service info.
Default: 10 requests per minute per IP address.
Configure in .env:
RATE_LIMIT_PER_MINUTE=10
Content is managed in Sanity CMS and synced to Supabase.
To sync updated content:
source venv/bin/activate
python sync_sanity.pyThis will:
- Clear existing documents from Supabase
- Fetch fresh content from Sanity
- Convert Portable Text to plain text
- Generate embeddings
- Store in Supabase with metadata
Deploy to any Python hosting platform:
- Railway
- Render
- Fly.io
- AWS Lambda (with Mangum adapter)
- Google Cloud Run
Make sure to set environment variables in your deployment platform.