Acceleracers Knowledge Base β a RAG-powered chatbot for the Hot Wheels Acceleracers universe.
Ask questions about characters, realms, accelechargers, drivers, and teams. The system scrapes the Acceleracers Fandom Wiki, indexes it into a local vector store, and answers with context retrieved from the corpus + an LLM.
Features:
- π Hybrid search (dense vectors + BM25) with MMR diversity reranking
- π¬ Chat history sidebar with localStorage persistence
- π§ Conversation context sent to the LLM across turns
- π Markdown rendering for responses
- π¦ Guardrails (rate limiting, max length)
- π’ Connection status indicator + periodic health checks
- π Toast notifications for transient errors (rate limits, validation)
β οΈ Inline error bubbles for server/network failures- π Source preview popover on hover
acceleracers-rag-demo.mp4
ββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββββββ
β React Client β β Hono Server β
β Tailwind CSS v4 βββββ>β POST /api/chat β SSE stream β
β react-markdown β β POST /api/query β JSON β
β lucide-react β β GET /api/health β
β β β Guardrails (rate-limit, max length) β
ββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββ β
β β Application (RAGService) β β
β β orchestrates use cases β β
β ββββββββββββ¬ββββββββββββββββββββββββββ β
β β β
β ββββββββββββΌββββββββββββββββββββββββββ β
β β Domain β β
β β Entities Β· Use Cases Β· Ports β β
β β MMR reranking Β· Conversation hist. β β
β ββββββββββββ¬ββββββββββββββββββββββββββ β
β β β
β ββββββββββββΌββββββββββββββββββββββββββ β
β β Infrastructure β β
β β Groq/Ollama Β· Vectra Β· MiniSearch β β
β β Fandom scraper Β· Vercel AI SDK β β
β ββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββ
Clean Architecture layers:
src/domain/β Entities, repository interfaces, use cases (zero external deps)src/application/β Service orchestration + config portssrc/infrastructure/β Adapters: Groq/Ollama (Vercel AI SDK), Vectra (vector store), MiniSearch (BM25), Fandom (scraper)src/presentation/β CLI REPL + Hono HTTP server with SSE streaming
RAG pipeline:
- Scrape Fandom wiki β
data/corpus.json - Semantic chunking (paragraph-aware, 1200 char chunks with 150 overlap)
- Embed chunks via Ollama
nomic-embed-textβ store in VectraLocalIndex - Hybrid retrieval: dense vector search + BM25 exact-match (MiniSearch) with RRF fusion
- MMR diversity reranking (Jaccard similarity, Ξ»=0.4) β top 6 chunks
- Generate answer via Groq (or Ollama) with proper system role, retrieved context + conversation history
- Node.js 22+
- Groq API key (free tier) for chat, or Ollama running locally as alternative
- For embeddings: Ollama with
nomic-embed-text:ollama pull nomic-embed-text
# Install server dependencies
npm install
# Install client dependencies (separate terminal or use full dev mode)
cd client && npm install && cd ..npm run dev # starts both server (:3000) and client (:5173) concurrentlyOpen http://localhost:5173 and start chatting.
npm run dev:server # Hono API server on http://localhost:3000
npm run dev:client # Vite dev server on http://localhost:5173npm run cli # interactive REPLdocker compose up # starts Ollama + appEnvironment variables (see .env.example):
| Variable | Default | Description |
|---|---|---|
CHAT_PROVIDER |
groq |
groq or ollama |
CHAT_MODEL |
llama-3.1-8b-instant |
Groq model; Ollama uses llama3.1:8b |
GROQ_API_KEY |
β | Required when CHAT_PROVIDER=groq |
EMBEDDING_PROVIDER |
ollama |
ollama only (Groq has no embedding models) |
EMBEDDING_MODEL |
nomic-embed-text |
Embedding model |
OLLAMA_URL |
http://localhost:11434 |
Base URL for Ollama |
CHUNK_SIZE |
1200 |
Characters per chunk |
CHUNK_OVERLAP |
150 |
Overlap between chunks |
TOP_K |
6 |
Chunks retrieved per query |
PORT |
3000 |
Server port |
{
"message": "Who is Vert Wheeler?",
"history": [{ "role": "user", "content": "..." }, { "role": "assistant", "content": "..." }]
}history is optional β include previous messages for conversation context.
Returns SSE events:
event: token
data: {"token":"Vert"}
event: token
data: {"token":" Wheeler"}
event: done
data: {"answer":"Vert Wheeler is...","sources":[{"title":"Vert Wheeler","url":"...","excerpt":"..."}]}
event: error
data: {"error":"Generation failed"}
The error event is sent if the LLM fails mid-stream.
{ "message": "Who is Vert Wheeler?" }
// Response: { "text": "Vert Wheeler is...", "sources": [{"title":"...","url":"...","excerpt":"..."}] }{ "status": "ok", "chatProvider": "groq", "chatModel": "llama-3.1-8b-instant", "embeddingProvider": "ollama", "embeddingModel": "nomic-embed-text" }data/corpus.jsonβ Scraped wiki pages (~306 pages, ~1.6MB)data/index/β Vectra vector index (~1,100 chunks, ~17MB)
Both are gitignored. Delete data/corpus.json to trigger a re-scrape.
| Layer | Technology |
|---|---|
| Server | Hono, TypeScript |
| Client | React 19, Vite, Tailwind CSS v4, lucide-react |
| LLM | Groq (llama-3.1-8b-instant) or Ollama (llama3.1:8b) via Vercel AI SDK |
| Embeddings | Ollama (nomic-embed-text) via Vercel AI SDK |
| Vector Store | Vectra (local) |
| BM25 Search | MiniSearch (exact-match, no fuzzy) |
| Scraping | Cheerio, Fandom API |
| Rendering | react-markdown, remark-gfm |
MIT