mirror of
https://github.com/mintlify/docs.git
synced 2026-09-14 13:35:46 +08:00
213 lines
6.0 KiB
Plaintext
213 lines
6.0 KiB
Plaintext
---
|
|
title: "Tutorial: Build an in-app documentation assistant"
|
|
sidebarTitle: "Build an in-app assistant"
|
|
description: "Embed the assistant in your application to answer questions with information from your documentation."
|
|
keywords: ["assistant embed", "in-app chat", "widget", "chatbot"]
|
|
---
|
|
|
|
## What you will build
|
|
|
|
A reusable widget that embeds the [assistant](/ai/assistant) directly in your application. The widget provides:
|
|
|
|
- A floating button that opens a chat panel when clicked
|
|
- Real-time streaming responses based on information from your documentation
|
|
- Message rendering with Markdown support
|
|
|
|
Users can use the widget to get help with your product without leaving your application.
|
|
|
|
<Frame>
|
|
<img src="/images/assistant/assistant-embed-demo.gif" alt="Demo of the assistant widget being opened and the user typing in How do I get started? Then the assistant responds." />
|
|
</Frame>
|
|
|
|
## Prerequisites
|
|
|
|
- [Mintlify Pro or Enterprise plan](https://mintlify.com/pricing)
|
|
- Your domain name, which appears at the end of your dashboard URL. For example, if your dashboard URL is `https://dashboard.mintlify.com/org-name/domain-name`, your domain name is `domain-name`
|
|
- An [assistant API key](https://dashboard.mintlify.com/settings/organization/api-keys)
|
|
- Node.js v18 or higher and npm installed
|
|
- Basic React knowledge
|
|
|
|
### Get your assistant API key
|
|
|
|
1. Navigate to the [API keys](https://dashboard.mintlify.com/settings/organization/api-keys) page in your dashboard.
|
|
2. Click **Create Assistant API Key**.
|
|
3. Copy the assistant API key (starts with `mint_dsc_`) and save it securely.
|
|
|
|
<Note>
|
|
The assistant API key is a public token that you can use in frontend code. Calls using this token count toward your plan's message allowance and can incur overages.
|
|
</Note>
|
|
|
|
## Set up the example
|
|
|
|
Clone the [example repository](https://github.com/mintlify/assistant-embed-example) and customize it for your needs.
|
|
|
|
<Steps>
|
|
<Step title="Clone the repository">
|
|
|
|
```bash
|
|
git clone https://github.com/mintlify/assistant-embed-example.git
|
|
cd assistant-embed-example
|
|
```
|
|
|
|
</Step>
|
|
<Step title="Choose your development tool">
|
|
The repository includes Next.js and Vite examples. Choose the tool you prefer to use.
|
|
|
|
<CodeGroup>
|
|
```bash title="Next.js"
|
|
cd nextjs
|
|
npm install
|
|
```
|
|
|
|
```bash title="Vite"
|
|
cd vite
|
|
npm install
|
|
```
|
|
</CodeGroup>
|
|
</Step>
|
|
<Step title="Configure your project">
|
|
|
|
Open `src/config.js` and update with your Mintlify project details.
|
|
|
|
```js src/config.js
|
|
export const ASSISTANT_CONFIG = {
|
|
domain: 'your-domain',
|
|
docsURL: 'https://yourdocs.mintlify.app',
|
|
};
|
|
```
|
|
|
|
Replace:
|
|
- `your-domain` with your Mintlify project domain found at the end of your dashboard URL.
|
|
- `https://yourdocs.mintlify.app` with your actual documentation URL.
|
|
|
|
</Step>
|
|
<Step title="Add your API token">
|
|
|
|
Create a `.env` file in the project root.
|
|
|
|
```bash .env
|
|
VITE_MINTLIFY_TOKEN=mint_dsc_your_token_here
|
|
```
|
|
|
|
Replace `mint_dsc_your_token_here` with your assistant API key.
|
|
|
|
</Step>
|
|
<Step title="Start the development server">
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
Open your application in a browser and click the **Ask** button to open the assistant widget.
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Customization ideas
|
|
|
|
### Source citations
|
|
|
|
Extract and display sources from assistant responses:
|
|
|
|
```jsx
|
|
const extractSources = (parts) => {
|
|
return parts
|
|
?.filter(p => p.type === 'tool-invocation' && p.toolInvocation?.toolName === 'search')
|
|
.flatMap(p => p.toolInvocation?.result || [])
|
|
.map(source => ({
|
|
url: source.url || source.path,
|
|
title: source.metadata?.title || source.path,
|
|
})) || [];
|
|
};
|
|
|
|
// In your message rendering:
|
|
{messages.map((message) => {
|
|
const sources = message.role === 'assistant' ? extractSources(message.parts) : [];
|
|
return (
|
|
<div key={message.id}>
|
|
{/* message content */}
|
|
{sources.length > 0 && (
|
|
<div className="mt-2 text-xs">
|
|
<p className="font-semibold">Sources:</p>
|
|
{sources.map((s, i) => (
|
|
<a key={i} href={s.url} target="_blank" rel="noopener noreferrer" className="text-blue-600">
|
|
{s.title}
|
|
</a>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
```
|
|
|
|
### Track conversation thread IDs
|
|
|
|
Store thread IDs to maintain conversation history across sessions:
|
|
|
|
```jsx
|
|
import { useState, useEffect } from 'react';
|
|
|
|
export function AssistantWidget({ domain, docsURL }) {
|
|
const [threadId, setThreadId] = useState(null);
|
|
|
|
useEffect(() => {
|
|
// Retrieve saved thread ID from localStorage
|
|
const saved = localStorage.getItem('assistant-thread-id');
|
|
if (saved) {
|
|
setThreadId(saved);
|
|
}
|
|
}, []);
|
|
|
|
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
|
|
api: `https://api.mintlify.com/discovery/v1/assistant/${domain}/message`,
|
|
headers: {
|
|
'Authorization': `Bearer ${import.meta.env.VITE_MINTLIFY_TOKEN}`,
|
|
},
|
|
body: {
|
|
fp: 'anonymous',
|
|
retrievalPageSize: 5,
|
|
...(threadId && { threadId }), // Include thread ID if available
|
|
},
|
|
streamProtocol: 'data',
|
|
sendExtraMessageFields: true,
|
|
fetch: async (url, options) => {
|
|
const response = await fetch(url, options);
|
|
const newThreadId = response.headers.get('x-thread-id');
|
|
if (newThreadId) {
|
|
setThreadId(newThreadId);
|
|
localStorage.setItem('assistant-thread-id', newThreadId);
|
|
}
|
|
return response;
|
|
},
|
|
});
|
|
|
|
// ... rest of component
|
|
}
|
|
```
|
|
|
|
### Add keyboard shortcuts
|
|
|
|
Allow users to open the widget and submit messages with keyboard shortcuts:
|
|
|
|
```jsx
|
|
useEffect(() => {
|
|
const handleKeyDown = (e) => {
|
|
// Cmd/Ctrl + Shift + I to toggle widget
|
|
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === 'I') {
|
|
e.preventDefault();
|
|
setIsOpen((prev) => !prev);
|
|
}
|
|
|
|
// Enter (when widget is focused) to submit
|
|
if (e.key === 'Enter' && !e.shiftKey && document.activeElement.id === 'assistant-input') {
|
|
e.preventDefault();
|
|
handleSubmit();
|
|
}
|
|
};
|
|
|
|
window.addEventListener('keydown', handleKeyDown);
|
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
}, [handleSubmit]);
|
|
```
|