
Portfolio Chatbot
The Problem
I wanted visitors to my portfolio site to be able to ask questions about my work - not just browse static pages, but actually have a conversation about my projects, experience, and skills. Traditional contact forms feel impersonal, and FAQ sections never cover the specific question someone has in mind.
What I Built
Portfolio Chatbot is a RAG-powered FastAPI service that answers questions about me using Supabase’s vector store with OpenAI embeddings and GPT models. It powers the live chat widget on my portfolio site, providing contextual answers drawn from my actual project documentation, experience records, and skill descriptions.
Architecture
- Ingestion - Content gets embedded into Supabase's pgvector extension using OpenAI's embedding model
- Retrieval - User questions are embedded, then matched via vector similarity search
- Generation - Relevant chunks are passed to a GPT model for answer generation
This ensures responses are grounded in my actual content, not generic AI outputs.
Technical Implementation
Ingestion Pipeline
I wrote a script that processes markdown files from my rag-data directory, chunks them intelligently (respecting section boundaries), and stores both the embeddings and original text. The chunking strategy matters - too small and you lose context, too large and retrieval becomes noisy.
FastAPI Service
The service handles CORS, rate limiting, and errors gracefully. It's deployed on Render with Docker, making it easy to update and scale. The frontend integration was seamless - just a fetch call to the API endpoint.
Edge Cases
- What if someone asks something not covered in my docs?
- What about ambiguous questions?
I implemented fallback responses that acknowledge limitations while still being helpful, and I log unanswered questions to identify content gaps.
Key Takeaway
RAG (Retrieval-Augmented Generation) is the most practical way to build AI that knows your specific content. It's not about making AI smarter - it's about giving it the right context to be useful.