diff --git a/docs.json b/docs.json index c2183be45..3c9d036f8 100644 --- a/docs.json +++ b/docs.json @@ -234,9 +234,10 @@ "icon": "bot", "pages": [ "guides/automate-agent", - "guides/geo", + "guides/assistant-embed", "guides/claude-code", "guides/cursor", + "guides/geo", "guides/windsurf" ] }, diff --git a/guides/assistant-embed.mdx b/guides/assistant-embed.mdx new file mode 100644 index 000000000..c5d84d71a --- /dev/null +++ b/guides/assistant-embed.mdx @@ -0,0 +1,222 @@ +--- +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" +--- + +## 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. + + +Demo of the assistant widget being opened and the user typing in How do I get started? Then the assistant responds. + + +## Prerequisites + +- [Mintlify Pro or Custom 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. + + + The assistant API key is a public token that can be used in frontend code. Calls using this token count toward your plan's message allowance and can incur overages. + + +## Set up the example + +The quickest way to get started is to clone the [example repository](https://github.com/mintlify/assistant-embed-example) and customize it for your needs. + + + + +```bash +git clone https://github.com/mintlify/assistant-embed-example.git +cd assistant-embed-example +npm install +``` + + + + +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. + + + + +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. + + + + +```bash +npm run dev +``` + +Open your application in a browser and click the **Ask** button to open the assistant widget. + + + + +## Project structure + +The example uses a component-based architecture. + +```text +src/ +├── App.css # App styles +├── App.jsx # Main app component that renders the widget +├── config.js # Configuration (domain and docsURL) +├── index.css # Global styles +├── main.jsx # Entry point +├── utils.js # Helper functions for parsing suggestions and extracting sources +└── components/ + ├── AssistantWidget.jsx # Main widget component with chat state and API logic + └── Message.jsx # Individual message component for rendering user and assistant messages +``` + +**Key files:** + +- **`src/App.jsx`**: Main app component. Shows how to import and use the `AssistantWidget` component. +- **`src/config.js`**: Centralized configuration. Update this file with your domain and docs URL. +- **`src/components/AssistantWidget.jsx`**: The main widget component. Manages the open/close state, chat messages, and API calls. +- **`src/utils.js`**: Contains utility functions for parsing the assistant's response format and extracting sources. +- **`src/components/Message.jsx`**: Renders individual messages with support for Markdown and suggestion links. + +## 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 ( +
+ {/* message content */} + {sources.length > 0 && ( +
+

Sources:

+ {sources.map((s, i) => ( + + {s.title} + + ))} +
+ )} +
+ ); +})} +``` + +### 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-dsc.mintlify.com/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]); +``` diff --git a/images/assistant/assistant-embed-demo.gif b/images/assistant/assistant-embed-demo.gif new file mode 100644 index 000000000..85594ede5 Binary files /dev/null and b/images/assistant/assistant-embed-demo.gif differ