Skip to content
HN On Hacker News ↗

GitHub - AniketWathore/bolnee-chat: Chatbot Integration in your Business website. Self hosted, free forever!

▲ 32 points 0 comments by AniketWathore 1w ago HN discussion ↗

Pangram verdict · v3.3

We believe that this entire text is AI.

99 %

AI likelihood · overall

AI
0% human-written 100% AI-generated
SEGMENTS · HUMAN 0 of 1
SEGMENTS · AI 1 of 1
WORD COUNT 1,235
PEAK AI % 99% · §1
Analyzed
Aug 30
backend: pangram/v3.3
Segments scanned
1 windows
avg 1235 words each
Distribution
0 / 100%
human / AI fraction
Verdict
AI
Pangram v3.3

Article text · 1,235 words · 1 segments analyzed

Human AI-generated
§1 AI · 99%

Chatbot integration in your business website. Self hosted, free forever! Bolnee-Chat is a self-hosted RAG chatbot platform. Create a bot, add your website + PDFs as knowledge, pick any OpenAI-compatible provider (OpenRouter, OpenAI, Groq, Ollama, vLLM), and embed a 2-line snippet. Answers are grounded in your sources with citations, visitor chats are grouped and exportable, and everything runs on your infrastructure with SQLite. Why Bolnee-Chat? Self-Hosted & Free Forever No vendor lock-in, no per-message billing. Run on your server, Vercel or Cloudflare Pages — SQLite, no external DB. RAG-Grounded Answers Crawls your site + ingests PDFs/TXT/MD/DOCX, chunks to SQLite FTS and builds grounded prompts. Sources are cited, fallback is configurable. 2-Line Embed, Any Stack Copy window.BotConfig + chatbot-widget.js and paste before </body>. Works on any site, accent/theme/greeting live via dashboard. All Features Bot Overview — Stats & Snippet Per-bot: Live status, message/user counts, creation date, source count, embed snippet with botName/avatar/chatUrl/accent/greeting/theme. Appearance — Live Preview Edit bot name, avatar (upload/preview), accent/background colour, theme light/dark/auto, greeting. Live preview; saved via PATCH /api/chatbots/:id. Chats — Grouped by Visitor Grouped by visitorId → IP, then by date, chronological. Refresh + download CSV (Excel) / JSON / PDF (print). Active sessions = distinct visitors last 5m. Settings — Provider, Prompts, Danger Zone provider/model/baseUrl/apiKey, default message (pre-first-turn), fallback message (no sources matched), delete bot + chats + sources + chunks. Widget — Floating, Theme-Aware, Persistent Bottom-right bubble → sliding window (360×520, 75vh mobile). Header with accent + avatar, typing dots, SSE streaming, sources cited, VISITOR_ID + history in localStorage so greeting shows once and chats survive close/open. Theme light/dark/auto (#0f172a / #fff). Also in the box: Knowledge management — lists locator · type · status · error · date with delete; append more via Add knowledge. Avatar file storage — data URLs converted to /api/public/avatar/:id (2MB limit, data/avatars/). Encrypted provider keys — per-bot apiKey/baseUrl/model via AES-256-GCM, never exposed in snippet. Dark-mode console — #020617 bg, #1e293b cards, slate-800 inputs, no white surfaces. Workflow 1. Create Chatbot — Brand in Seconds Name + avatar (PNG/JPG/WEBP ≤2MB, preview) → stored as /api/public/avatar/:id and shown in the widget header. 2. Add Knowledge — Website + Files URL-only, files-only, or both. Same-origin crawler (crawler/crawler.py) respects robots.txt, extracts h1/h2/p/li, dedups, saves data/{chatbotId}_website.json. Status: queued → crawling → parsing → indexing → indexed. 3. Configure Provider — Any OpenAI-Compatible API Pick provider → Base URL auto-fills → paste API key → Fetch models lists live models (prioritizes :free for OpenRouter). Keys stored encrypted (AES-256-GCM), never in embed. 4. Embed — 2 Lines Copy from Overview → Embed code or Knowledge → Step 4. Auto-configures origin via window.location.origin; widget loads via chatbot-widget.js with SSE streaming. Requirements Requirement Details OS macOS, Linux, Windows (WSL) Runtime Node.js 18+ Package Manager npm Python 3.10+ (crawler, optional but recommended) Python Deps aiohttp, beautifulsoup4, lxml, requests, brotli (+ playwright for JS-heavy sites) Tech Stack Installation # Clone git clone https://github.com/AniketWathore/bolnee-chat.git cd bolnee-chat # Env cp .env.example .env # edit .env — simplest self-hosted: # DISABLE_AUTH=true # JWT_SECRET=change-me-32-chars # LLM_BASE_URL=https://openrouter.ai/api/v1 # optional global fallback # LLM_API_KEY=sk-or-v1-... # optional global fallback # LLM_MODEL=inclusionai/ling-3.0-flash-fin:free # Install npm install # Python crawler deps (optional) pip install aiohttp beautifulsoup4 lxml requests brotli # Verify npm run lint # tsc --noEmit npm run build # vite + esbuild → dist/ npm run dev # http://localhost:3000 (auto-fallback to 3001 if busy) SQLite is created at data/bolnee.db (git-ignored). Crawled sites → data/{chatbotId}_website.json, chunks in SQLite. Usage — Dashboard Flow Create chatbot — + New chatbot → name + avatar (preview ≤2MB). Add knowledge — enter https://your-site.com and/or upload PDF/TXT/MD/DOCX/FAQ → status queued → indexed. Configure provider — choose provider → Fetch models → pick model → Save. Keys encrypted, not in embed. Embed — copy snippet from Overview: <script> window.BotConfig = { botName: "Customer Bot", avatar: "https://your-domain/api/public/avatar/BOT_ID", chatUrl: "https://your-domain/api/public/chat/BOT_ID", accentColor: "#111111", greeting: "Hi! How can I help?", theme: "dark" }; </script> <script src="https://your-domain/chatbot-widget.js" async></script> Paste before </body>. Widget stores VISITOR_ID + chat history in localStorage; greeting shows once. Bot Console Reference Tab What it does Overview Live status, messages/users/sources, embed copy (src/components/ChatbotDashboard.tsx:244) Appearance name/avatar/accent/theme/greeting + live preview (src/components/ChatbotDashboard.tsx:282) Chats Grouped by visitor → date, CSV/JSON/PDF, Refresh (src/components/ChatbotDashboard.tsx:371) Knowledge Sources + Add knowledge wizard (src/components/ChatbotDashboard.tsx:449) Settings provider/model/baseUrl/apiKey, defaultMessage/fallbackMessage, Danger zone delete (src/components/ChatbotDashboard.tsx:493) API Reference Method Path Description POST /api/chatbots Create bot GET /api/chatbots List bots PATCH /api/chatbots/:id Appearance + provider (name/avatar/accent/theme/greeting + provider/model/apiKey/baseUrl) GET /api/chatbots/:id/appearance Get appearance (server.ts:728) GET /api/chatbots/:id/messages?limit=200 Grouped messages GET /api/chatbots/:id/stats total/users GET /api/chatbots/:id/messages/export?format=csv|json Export GET /api/knowledge/sources?chatbotId=ID List sources POST /api/knowledge/sources/:chatbotId Add URL ({url}) or file (multipart) → queued DELETE /api/knowledge/sources/:sourceId?chatbotId=ID Delete source + chunks POST /api/public/chat/:chatbotId SSE chat {message, visitorId} → data: {token|error|sources} + data: [DONE] GET /api/public/knowledge/:chatbotId Public knowledge (cached) GET /api/public/avatar/:chatbotId Avatar file or redirect POST /api/providers/models List models for provider/baseUrl/apiKey GET /api/stats Global totalMessages/activeSessions Streaming: public/chatbot-widget.js:311 reads SSE via getReader(), falls back to text() + SW bypass for locked streams. Visitor grouping via X-Visitor-Id (VISITOR_ID in localStorage). File Reference Path Role server.ts Express + Vite dev, auth (DISABLE_AUTH), ingestion, RAG, SSE chat (server.ts:282) server/db.ts SQLite (better-sqlite3) — chatbots/sources/chunks/messages, getChatbotAppearance server/ingestion.ts + crawler/run_crawler_for_bolnee.py Crawl → /data/{id}_website.json → chunks crawler/crawler.py Same-origin crawl, robots.txt, h1/h2/p/li extraction, sitemap + homepage public/chatbot-widget.js Embeddable widget — BotConfig.chatUrl, accent, greeting, theme, VISITOR_ID, history src/components/ChatbotDashboard.tsx Tabs: overview/appearance/chats/knowledge/settings, embedCode with theme src/components/KnowledgeSection.tsx 4-step wizard: Knowledge → Provider → Processing (polls status) → Embed src/components/Overview.tsx Stats + grid of 4 bots + View all src/components/BotCreationWizard.tsx Name + avatar upload (2MB limit) src/index.css Dark-mode tokens (--color-bg #020617, --color-card #1e293b) vercel.json / wrangler.toml Hosting rewrites, bucket = "./dist", DISABLE_AUTH Hosting Dashboard is fully API-driven (/api/* relative) and auto-configures window.location.origin for embed URLs. Vercel: # env DISABLE_AUTH=true # JWT_SECRET not required for simple mode # vercel.json already: rewrites /api/:path* → /api, /(.*) → /index.html, outputDirectory: dist npm run build && vercel --prod Cloudflare Pages / Workers: # wrangler.toml: bucket = "./dist", DISABLE_AUTH=true npm run build wrangler pages deploy dist # or: npx wrangler deploy Chat endpoint streams SSE; for external sites use public https:// chatUrl (not localhost). Configuration Env Description Default DISABLE_AUTH / VITE_DISABLE_AUTH No-login console (single-tenant) false JWT_SECRET Auth signing key (16+ chars, prod required) development-secret-change-me LLM_BASE_URL / OPENROUTER_API_KEY / NVIDIA_API_KEY Global provider fallback (per-bot settings take precedence) — LLM_API_KEY Global API key fallback — LLM_MODEL Global model fallback (e.g. openai/gpt-4o-mini) gpt-4o-mini PORT Server port (auto-fallback +1 if busy) 3000 .env.example documents all. Troubleshooting Symptom Fix Port 3000 in use → 3001 and embed fails on external site Embed uses window.location.origin; regenerate after restart or deploy to public URL (localhost embed is https:// mixed-content) getReader locked / ReadableStream locked Bump public/sw.js to v3 skips POST /api/public/chat; hard-refresh to update SW Model 404 / 402 Use Fetch models → pick :free (e.g. inclusionai/ling-3.0-flash-fin:free) or add credits 404 knowledge/avatar Ensure data/bolnee.db exists and bot id matches data/{id}_website.json Avatar too large PNG/JPG/WEBP ≤2MB; data URLs auto-converted to /api/public/avatar/:id Greeting repeats on open/close Fixed in public/chatbot-widget.js:115 — saveHistory/loadHistory in localStorage + engine=true guard; clear bolnee_msgs_* to reset Verification Checklist npm run lint # tsc --noEmit clean npm run build # vite + esbuild → dist/ npm run dev # http://localhost:3000 # Manual: # 1. Create bot → avatar preview → Save appearance → preview updates # 2. Add knowledge: URL + PDF → status queued → indexed # 3. Provider → Fetch models → pick :free → Save # 4. Overview → Copy embed → paste in plain HTML → widget loads, greeting once, close/open keeps history, dark/light/auto themes correct