Static portfolios often lack the ability to dynamically surface relevant technical details based on specific queries. I needed a system that could intelligently parse my experience and provide instant, contextually relevant answers without manual navigation.

Built the full RAG pipeline solo: ingestion script, pgvector search, Gemini primary + OpenRouter fallback orchestration, and IPv4-forced HTTPS for network reliability. All in one sprint.
Built build-chunks.ts to split portfolio JSON into semantic chunks, embed via Gemini text-embedding-004 (768 dims), and upsert into Supabase pgvector. 1500ms batch delays respect the free-tier 15 RPM limit. All 143 chunks indexed cleanly.
const embedding = await ai.models.embedContent({
model: 'text-embedding-004',
contents: [{ parts: [{ text: chunk.content }] }],
});
await supabase.from('portfolio_chunks').upsert({
id: chunk.id,
content: chunk.content,
embedding: embedding.embeddings[0].values, // 768 dims
metadata: chunk.metadata,
});
await new Promise(r => setTimeout(r, 1500)); // respect 15 RPMEach user query is embedded and matched against all chunks via pgvector's <=> cosine distance operator. Top-5 results are injected as context into the AI prompt — giving the model grounded, factual answers with zero hallucination.
SELECT content, metadata,
1 - (embedding <=> query_embedding) AS similarity
FROM portfolio_chunks
ORDER BY similarity DESC
LIMIT 5;The /api/chat route tries Gemini first (3 retries on 503). On 429 quota hit, it silently switches to OpenRouter Gemma 3 12B. If OpenRouter also fails, it returns a polite chat message — never a broken UI. IPv4-forced HTTPS bypasses ISP DNS timeouts entirely.
try {
reply = await geminiPost(apiKey, body); // primary
} catch (err) {
if (err.statusCode === 429) {
// Fallback: OpenRouter Gemma 3 12B (free tier)
reply = await openRouterPost(openRouterKey, body);
} else throw err;
}
// Outer catch: return graceful UI message, never 500143 chunks indexed. Chatbot answers complex technical questions in <2s with factual, grounded context. Zero UI downtime across all failure scenarios. Built solo in one sprint at effectively $0 cost.
"143 semantic knowledge chunks indexed from real project data. Sub-200ms retrieval with triple-redundancy failover — zero downtime across all tested failure scenarios, built solo at effectively $0 cost."