Chat Window
Part of Kiri Chat — a floating, embeddable chat widget that lets users have conversations with an AI assistant powered by your documentation.
What is this component?
The chat window is the user-facing interface of Kiri Chat. It's a web component (<chat-button>) that provides a floating chat button on every page, allowing users to ask natural language questions about the documentation and receive AI-generated answers with source attribution.
Features
- Web Component (
<chat-button>) — drop-in custom element, no framework required - Markdown rendering — bot responses are rendered with
markedfor rich text, code blocks, and lists - Source attribution — each response links back to the documentation sections used as context
- Loading spinner — animated indicator while the API processes the request
- Auto-inject — the chat button is automatically appended to
document.bodyon page load
Architecture
flowchart LR
A[chat-button.js<br/>Web Component] -->|POST /chat| B[FastAPI<br/>chat-api/main.py]
B --> C[Qdrant<br/>Docker]
B <--> D[Ollama<br/>127.0.0.1:11434]
A -->|marked.js| E[Browser<br/>markdown rendering]
Files
docfx-site/
├── chat-button.js # Web Component (<chat-button>)
├── chat-api/
│ └── main.py # FastAPI RAG backend (serves /chat)
└── docs/
└── chat-window.md # This documentation
How It Works
1. Component Initialization
The <chat-button> custom element is defined in chat-button.js. On page load, a self-executing function checks for an existing <chat-button> and injects one if missing:
(function() {
function injectChatButton() {
if (!document.querySelector('chat-button')) {
const chatButton = document.createElement('chat-button');
document.body.appendChild(chatButton);
}
}
// ...
})();
2. User Interaction
- User clicks the floating chat button (bottom-right corner)
- Chat window opens with a message input and message history
- User types a question and presses Enter or clicks Send
- A loading spinner ("Thinking...") appears while the request is pending
3. API Request
The component sends a POST request to the chat API:
const response = await fetch('http://localhost:8000/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: text })
});
4. Response Rendering
- The bot's response (Markdown) is parsed with
markedand inserted as HTML - Source links are extracted from
data.sourcesand rendered as clickable badges - Each source link points to the exact documentation section used as context
API Response Format
The chat API returns:
{
"response": "Based on the documentation...",
"sources": [
{
"url": "http://localhost:8080/docs/getting-started.html#prerequisites",
"header": "Prerequisites",
"source": "docs/getting-started.md"
}
]
}
Styling
The component uses Shadow DOM for style encapsulation. Key CSS classes:
| Class | Purpose |
|---|---|
.chat-button |
Floating action button (60×60px circle) |
.chat-window |
Chat panel (350×500px, hidden by default) |
.chat-messages |
Scrollable message container |
.message.user |
User messages (blue, right-aligned) |
.message.bot |
Bot messages (white, left-aligned, Markdown-rendered) |
.message.loading |
Loading spinner container |
.spinner |
CSS-animated rotating circle |
.message-sources |
Source attribution section |
.sources-label |
"Sources:" label |
Configuration
The chat button connects to the API at http://localhost:8000/chat. To change the endpoint, update the fetch call in sendMessage():
const response = await fetch('YOUR_API_URL/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: text })
});
Usage
Automatic Injection (Default)
The chat button automatically appears on any page that loads chat-button.js:
<script src="path/to/chat-button.js"></script>
Manual Injection
To control placement, add the element directly in your HTML:
<chat-button></chat-button>
<script src="path/to/chat-button.js"></script>
Dependencies
| Dependency | Purpose | Loading |
|---|---|---|
marked (CDN) |
Markdown-to-HTML rendering | Lazy-loaded on first message |
FastAPI /chat |
RAG backend endpoint | Required at runtime |
| Ollama | Local LLM for responses | Required at runtime |
| Qdrant | Vector search for context | Required at runtime |
Notes
- The
markedlibrary is loaded on-demand (first message) to avoid blocking page load - The chat window opens at 350×500px and floats above all other content (
z-index: 9999) - The input field is automatically cleared after sending
- If the API is unreachable, an error message is displayed in the chat window