A self-hosted AI chat agent that blooms on your website.
Upload your documents, embed a lightweight chat widget, and let SakurAI answer your visitors' questions — grounded in your own content, powered by RAG.
Quick Start • Features • How It Works • Embed Widget • Deployment Guide • Custom Tools
Drop a single <script> tag into any site and you get a polished AI assistant that actually knows your stuff. No third-party SaaS, no per-seat pricing — just your server, your data, your agent.
Configure your agent's personality, appearance, knowledge base, and get your embed code — all from one place.
Upload your text / documents and SakurAI will use them to answer questions with accurate, grounded responses.
The agent maintains context throughout the conversation and uses RAG context. Each new session starts fresh.
- Knowledge Base (RAG) — Upload PDFs, Word docs, text, JSON, CSV, or Markdown files. SakurAI uses vector embeddings to find relevant context before answering.
- Embeddable Widget — One
<script>tag on any website — WordPress, Shopify, plain HTML, anything. - Admin Dashboard — Configure your agent's personality, appearance, knowledge base, and tools from a clean web UI.
- Conversation Memory — Chat sessions persist across page reloads with automatic conversation summaries.
- Custom Tools — Give your agent the ability to call APIs, query databases, or perform actions. See TOOLS.md for details.
- Zero Configuration —
docker-compose up -dand you're live. Default admin credentials are created on first boot. - Rate Limiting & Security — Built-in throttling, Helmet.js security headers, JWT auth, and bcrypt password hashing.
Note
SakurAI currently uses Google Gemini as its AI provider (chat, embeddings, and tool calling). Multi-provider support (OpenAI, Claude, etc.) is not available yet — contributions are welcome!
You only need Docker and a free Google Gemini API Key.
git clone https://github.com/Jergasus/SakurAI.git && cd SakurAI
cp .env.example .env
# Set your GEMINI_API_KEY in .env
docker-compose up -d --buildOpen http://localhost and log in with admin@sakurai.com / admin123.
Warning
Change the default credentials immediately via the Account tab in the dashboard. Also set a strong JWT_SECRET in your .env before exposing the app to the internet.
From the admin dashboard, go to Install, copy the snippet, and drop it into your HTML:
<script src="http://localhost/widget/widget.js"
data-api-key="YOUR_API_KEY"
data-api-url="http://localhost/api"></script>That's it — a floating chat button appears in the bottom-right corner of your site.
Tip
Replace localhost with your server's domain or IP when deploying to production. The widget works on any website — WordPress, Shopify, static HTML, etc.
Your visitor's browser Your server (one VPS)
┌─────────────┐ ┌──────────────────────────┐
│ <script> │ ──── loads ────▶ │ Nginx (:80) │
│ widget.js │ │ ├── Admin dashboard │
│ │ │ ├── widget.js │
│ User types │ │ └── /api/* proxy ──┐ │
│ a message │ ── /api/* ────▶ │ ▼ │
│ │ │ NestJS API (internal) │
│ │ ◀── response ── │ ├── RAG vector search │
│ AI replies │ │ ├── Gemini AI call │
└─────────────┘ │ └── Session persistence │
│ │
│ MongoDB (internal) │
└──────────────────────────┘
- Your visitor loads
widget.js— a floating chat button appears - They send a message — the widget calls your API
- SakurAI searches your knowledge base using vector similarity
- Top matches + the question go to Google Gemini
- Gemini responds and the answer blooms in the widget
.
├── api/ # Backend (NestJS)
│ └── src/
│ ├── auth/ # JWT authentication
│ ├── bootstrap/ # Auto-creates default admin on first run
│ ├── chat/ # Chat endpoint, session history, analytics
│ ├── knowledge/ # RAG: ingestion, PDF processing, vector search
│ ├── schemas/ # MongoDB schemas
│ ├── tenants/ # Tenant CRUD, account management
│ ├── tools/ # Tool registry and custom tool interface
│ ├── app.module.ts
│ └── main.ts
│
├── web/ # Frontend (Angular)
│ └── src/
│ ├── app/
│ │ ├── components/ # Chat widget (dashboard preview)
│ │ ├── guards/ # Auth route guard
│ │ ├── interceptors/# JWT token interceptor
│ │ ├── pages/ # Login, Admin dashboard, Public chat
│ │ ├── services/ # API clients
│ │ └── widget/ # Embeddable Web Component (Shadow DOM)
│ ├── environments/
│ ├── main.ts
│ └── widget.ts # Widget entry point → widget.js
│
├── docker-compose.yml
├── .env.example
├── DEPLOY.md # Full deployment & production guide
└── TOOLS.md # How to create custom tools
| Layer | Technology |
|---|---|
| AI | Google Gemini 2.5 Flash + Embedding API |
| Backend | NestJS, Mongoose, JWT, Helmet |
| Frontend | Angular, Tailwind CSS |
| Widget | Angular Elements (Web Component, Shadow DOM) |
| Database | MongoDB 7 |
| Deployment | Docker Compose, Nginx |
All configuration is done via environment variables in .env. See .env.example for the full list.
| Variable | Default | Purpose |
|---|---|---|
GEMINI_API_KEY |
(required) | Google AI API key |
JWT_SECRET |
change-me-in-production |
Auth token signing key |
VECTOR_SEARCH_MODE |
local |
local (in-memory cosine) or atlas (MongoDB Atlas) |
CORS_ALLOW_ALL |
true |
Allow widget embedding from any domain |
THROTTLE_LIMIT |
60 |
Max requests per minute per IP |
WEB_PORT |
80 |
Host port (dashboard + API via Nginx proxy) |
DEFAULT_ADMIN_* |
admin@sakurai.com / admin123 |
First-run seed credentials |
Note
The default VECTOR_SEARCH_MODE=local uses in-memory cosine similarity, which works well for small-to-medium knowledge bases. For 5,000+ documents, switch to atlas mode with a MongoDB Atlas vector search index.
For production setup (HTTPS, MongoDB Atlas, CORS), see the Deployment Guide.
Each SakurAI deployment runs one agent with its own knowledge base, configuration, and API key. If you need separate agents for different projects, run a separate instance for each:
# Agent 1 (default port 80)
cp -r SakurAI agent-1 && cd agent-1
# Edit .env: set GEMINI_API_KEY and credentials
docker-compose up -d
# Agent 2 (different port)
cp -r SakurAI agent-2 && cd agent-2
# Edit .env: set WEB_PORT=8080 and your GEMINI_API_KEY
docker-compose up -dEach instance is fully isolated — separate database, separate knowledge base, separate admin account.
Tip
You only need to change WEB_PORT in .env to avoid port conflicts. Docker Compose uses the folder name to isolate containers, networks, and volumes automatically. If using MongoDB Atlas, set a different database name in MONGO_URI for each instance (e.g., mongodb+srv://.../agent_1 and mongodb+srv://.../agent_2).
If you like my work, you can support me:





