react-docs-module 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +279 -0
  2. package/ai-chat.tsx +222 -0
  3. package/chat-api.ts +90 -0
  4. package/cn.ts +15 -0
  5. package/config.ts +29 -0
  6. package/dist/ai-chat.d.ts +12 -0
  7. package/dist/ai-chat.js +72 -0
  8. package/dist/ai-chat.js.map +1 -0
  9. package/dist/chat-api.d.ts +16 -0
  10. package/dist/chat-api.js +62 -0
  11. package/dist/chat-api.js.map +1 -0
  12. package/dist/cn.d.ts +4 -0
  13. package/dist/cn.js +14 -0
  14. package/dist/cn.js.map +1 -0
  15. package/dist/config.d.ts +14 -0
  16. package/dist/config.js +15 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/doc-pagination.d.ts +13 -0
  19. package/dist/doc-pagination.js +8 -0
  20. package/dist/doc-pagination.js.map +1 -0
  21. package/dist/docs-index.d.ts +7 -0
  22. package/dist/docs-index.js +11 -0
  23. package/dist/docs-index.js.map +1 -0
  24. package/dist/docs-page.d.ts +15 -0
  25. package/dist/docs-page.js +38 -0
  26. package/dist/docs-page.js.map +1 -0
  27. package/dist/docs-sidebar.d.ts +18 -0
  28. package/dist/docs-sidebar.d.ts.map +1 -0
  29. package/dist/docs-sidebar.js +27 -0
  30. package/dist/docs-sidebar.js.map +1 -0
  31. package/dist/documentation-layout.d.ts +15 -0
  32. package/dist/documentation-layout.js +20 -0
  33. package/dist/documentation-layout.js.map +1 -0
  34. package/dist/heading.d.ts +10 -0
  35. package/dist/heading.js +16 -0
  36. package/dist/heading.js.map +1 -0
  37. package/dist/index.d.ts +18 -0
  38. package/dist/index.js +19 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/mdx/callouts.d.ts +8 -0
  41. package/dist/mdx/callouts.js +8 -0
  42. package/dist/mdx/callouts.js.map +1 -0
  43. package/dist/mdx/code-block.d.ts +8 -0
  44. package/dist/mdx/code-block.js +29 -0
  45. package/dist/mdx/code-block.js.map +1 -0
  46. package/dist/mdx/components.d.ts +13 -0
  47. package/dist/mdx/components.js +21 -0
  48. package/dist/mdx/components.js.map +1 -0
  49. package/dist/mdx.d.ts +20 -0
  50. package/dist/mdx.js +109 -0
  51. package/dist/mdx.js.map +1 -0
  52. package/dist/search-index.d.ts +10 -0
  53. package/dist/search-index.js +38 -0
  54. package/dist/search-index.js.map +1 -0
  55. package/dist/search.d.ts +6 -0
  56. package/dist/search.js +142 -0
  57. package/dist/search.js.map +1 -0
  58. package/dist/table-of-contents-provider.d.ts +4 -0
  59. package/dist/table-of-contents-provider.js +30 -0
  60. package/dist/table-of-contents-provider.js.map +1 -0
  61. package/dist/table-of-contents.d.ts +11 -0
  62. package/dist/table-of-contents.js +9 -0
  63. package/dist/table-of-contents.js.map +1 -0
  64. package/dist/theme-context.d.ts +20 -0
  65. package/dist/theme-context.js +28 -0
  66. package/dist/theme-context.js.map +1 -0
  67. package/dist/tsconfig.tsbuildinfo +1 -0
  68. package/dist/ui/button.d.ts +12 -0
  69. package/dist/ui/button.js +34 -0
  70. package/dist/ui/button.js.map +1 -0
  71. package/dist/ui/dialog.d.ts +17 -0
  72. package/dist/ui/dialog.js +22 -0
  73. package/dist/ui/dialog.js.map +1 -0
  74. package/dist/ui/input.d.ts +4 -0
  75. package/dist/ui/input.js +9 -0
  76. package/dist/ui/input.js.map +1 -0
  77. package/dist/util.d.ts +59 -0
  78. package/dist/util.js +96 -0
  79. package/dist/util.js.map +1 -0
  80. package/doc-pagination.tsx +67 -0
  81. package/docs-index.tsx +17 -0
  82. package/docs-page.tsx +68 -0
  83. package/docs-sidebar.tsx +165 -0
  84. package/documentation-layout.tsx +99 -0
  85. package/heading.tsx +63 -0
  86. package/index.ts +28 -0
  87. package/mdx/callouts.tsx +29 -0
  88. package/mdx/code-block.tsx +89 -0
  89. package/mdx/components.tsx +55 -0
  90. package/mdx.ts +138 -0
  91. package/package.json +99 -0
  92. package/search-index.ts +52 -0
  93. package/search.tsx +273 -0
  94. package/table-of-contents-provider.tsx +43 -0
  95. package/table-of-contents.tsx +44 -0
  96. package/theme-context.tsx +57 -0
  97. package/ui/button.tsx +56 -0
  98. package/ui/dialog.tsx +108 -0
  99. package/ui/input.tsx +22 -0
  100. package/util.ts +169 -0
package/README.md ADDED
@@ -0,0 +1,279 @@
1
+ # React Docs Module
2
+
3
+ A powerful, embeddable documentation system with built-in search and AI chat capabilities. Perfect for creating beautiful, interactive documentation pages with minimal setup.
4
+
5
+ ## Features
6
+
7
+ - 🎨 **Themeable** - Customize colors and appearance via `docs.json` configuration
8
+ - 🔍 **Full-text Search** - Fast, client-side search with caching
9
+ - 🤖 **AI Chat** - Integrated AI assistant for documentation Q&A
10
+ - 📱 **Responsive** - Mobile-friendly design with adaptive layouts
11
+ - ⚡ **Fast** - Built with Next.js and optimized for performance
12
+ - 🎯 **TypeScript** - Full type safety and excellent DX
13
+ - 📝 **MDX Support** - Rich content with React components
14
+ - 📋 **Mintlify Compatible** - Full support for Mintlify docs.json schema
15
+
16
+ ## Quick Start
17
+
18
+ ### 1. Installation
19
+
20
+ ```bash
21
+ npm install react-docs-module
22
+ ```
23
+
24
+ ### 2. Configuration
25
+
26
+ Create a `docs.json` file with your documentation configuration using the **Mintlify schema**:
27
+
28
+ ```json
29
+ {
30
+ "$schema": "https://leaves.mintlify.com/schema/docs.json",
31
+ "theme": "mint",
32
+ "name": "My Documentation",
33
+ "description": "Comprehensive documentation for my project",
34
+ "logo": {
35
+ "dark": "/assets/logo-dark.png",
36
+ "light": "/assets/logo-light.png"
37
+ },
38
+ "favicon": "/assets/favicon.png",
39
+ "colors": {
40
+ "primary": "#3B82F6",
41
+ "light": "#60A5FA",
42
+ "dark": "#1D4ED8"
43
+ },
44
+ "navbar": {
45
+ "cta": {
46
+ "type": "github",
47
+ "url": "https://github.com/your-org/your-repo"
48
+ }
49
+ },
50
+ "navigation": {
51
+ "groups": [
52
+ {
53
+ "group": "Getting Started",
54
+ "pages": [
55
+ "introduction",
56
+ "installation",
57
+ "quick-start"
58
+ ]
59
+ },
60
+ {
61
+ "group": "API Reference",
62
+ "pages": [
63
+ "api/overview",
64
+ "api/authentication"
65
+ ]
66
+ }
67
+ ]
68
+ },
69
+ "footer": {
70
+ "socials": {
71
+ "github": "https://github.com/your-org/your-repo",
72
+ "twitter": "https://twitter.com/your-handle"
73
+ }
74
+ },
75
+ "feedback": {
76
+ "thumbsRating": true
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### 3. Basic Usage
82
+
83
+ ```tsx
84
+ import { DocumentationLayout, createReactDocsConfig } from 'react-docs-module';
85
+
86
+ // Create config with defaults or custom overrides
87
+ const config = createReactDocsConfig({
88
+ basePath: "/docs",
89
+ contentPath: "content/docs",
90
+ // searchApiPath and aiChatApiPath use defaults
91
+ });
92
+
93
+ export default function DocsPage() {
94
+ return (
95
+ <DocumentationLayout
96
+ config={config}
97
+ navigation={navigation}
98
+ currentPath="/docs/introduction"
99
+ headings={headings}
100
+ >
101
+ <div>Your documentation content here</div>
102
+ </DocumentationLayout>
103
+ );
104
+ }
105
+ ```
106
+
107
+ ## Configuration
108
+
109
+ ### ReactDocsConfig
110
+
111
+ ```typescript
112
+ interface ReactDocsConfig {
113
+ basePath: string; // Base URL path for docs
114
+ contentPath: string; // Path to MDX content files
115
+ searchApiPath: string; // API endpoint for search index
116
+ aiChatApiPath: string; // API endpoint for AI chat
117
+ }
118
+
119
+ // Factory function with optional overrides
120
+ function createReactDocsConfig(options?: ReactDocsConfigOptions): ReactDocsConfig
121
+
122
+ interface ReactDocsConfigOptions {
123
+ basePath?: string; // Default: "/docs"
124
+ contentPath?: string; // Default: "content/docs"
125
+ searchApiPath?: string; // Default: "/api/docs/search-index"
126
+ aiChatApiPath?: string; // Default: "/api/docs/chat"
127
+ }
128
+ ```
129
+
130
+ ### Configuration Examples
131
+
132
+ ```typescript
133
+ // Use all defaults
134
+ const config = createReactDocsConfig();
135
+
136
+ // Override specific fields
137
+ const config = createReactDocsConfig({
138
+ basePath: "/documentation",
139
+ aiChatApiPath: "/api/custom-chat"
140
+ });
141
+
142
+ // Override all fields
143
+ const config = createReactDocsConfig({
144
+ basePath: "/my-docs",
145
+ contentPath: "docs",
146
+ searchApiPath: "/api/search",
147
+ aiChatApiPath: "/api/ai-chat"
148
+ });
149
+ ```
150
+
151
+ ### docs.json Schema (Mintlify Compatible)
152
+
153
+ The `docs.json` file uses the complete **[Mintlify schema](https://leaves.mintlify.com/schema/docs.json)** for full compatibility:
154
+
155
+ - **Required**: `theme`, `name`, `colors.primary`, `navigation`
156
+ - **Optional**: `description`, `logo`, `favicon`, `navbar`, `footer`, `feedback`, and more
157
+ - **Migration**: Existing Mintlify projects can use their `mint.json` structure in `docs.json`
158
+
159
+ ## Components
160
+
161
+ ### Core Components
162
+
163
+ - `DocumentationLayout` - Main layout wrapper with sidebar and TOC
164
+ - `Search` - Search component with AI chat integration
165
+ - `DocsIndex` - Documentation index/landing page
166
+ - `DocsSidebar` - Navigation sidebar
167
+ - `TableOfContents` - Page table of contents
168
+ - `DocPagination` - Previous/next page navigation
169
+
170
+ ### Theme System
171
+
172
+ ```tsx
173
+ import { DocsThemeProvider, useDocsColors } from 'react-docs-module';
174
+
175
+ function CustomComponent() {
176
+ const colors = useDocsColors();
177
+
178
+ return (
179
+ <div style={{ color: colors.primary }}>
180
+ Themed content
181
+ </div>
182
+ );
183
+ }
184
+ ```
185
+
186
+ ### AI Chat Integration
187
+
188
+ ```tsx
189
+ import { streamDocsChatResponse } from 'react-docs-module/chat-api';
190
+
191
+ // API route example
192
+ export async function POST(req: Request) {
193
+ const { messages } = await req.json();
194
+
195
+ return streamDocsChatResponse(
196
+ config,
197
+ messages,
198
+ "You are a helpful documentation assistant.",
199
+ async (result) => {
200
+ // Handle completion
201
+ console.log(result.text);
202
+ }
203
+ );
204
+ }
205
+ ```
206
+
207
+ ## API Reference
208
+
209
+ ### Functions
210
+
211
+ - `getDocsSidebar(config)` - Generate sidebar navigation from docs.json
212
+ - `getAllDocs(config)` - Get all documentation files metadata
213
+ - `getAllDocsContent(config)` - Get all documentation content (cached)
214
+ - `getDocBySlug(config, slug)` - Get specific document by slug
215
+ - `buildSearchIndex(config)` - Build search index from content
216
+ - `streamDocsChatResponse(...)` - Stream AI chat responses
217
+
218
+ ### Types
219
+
220
+ - `ReactDocsConfig` - Main configuration interface
221
+ - `ReactDocsConfigOptions` - Configuration factory options
222
+ - `DocsJsonConfig` - docs.json configuration schema (Mintlify compatible)
223
+ - `ThemeColors` - Color theme interface
224
+ - `ModelProvider` - AI model provider configuration
225
+
226
+ ## Advanced Usage
227
+
228
+ ### Custom Search API
229
+
230
+ ```typescript
231
+ // pages/api/search-index.ts
232
+ import { buildSearchIndex, createReactDocsConfig } from 'react-docs-module';
233
+
234
+ const DOCS_CONFIG = createReactDocsConfig({
235
+ contentPath: "content/docs"
236
+ });
237
+
238
+ export default async function handler(req, res) {
239
+ const searchIndex = await buildSearchIndex(DOCS_CONFIG);
240
+ res.json(searchIndex);
241
+ }
242
+ ```
243
+
244
+ ### Custom AI Models
245
+
246
+ ```typescript
247
+ const modelProvider: ModelProvider = {
248
+ providerType: 'anthropic',
249
+ model: 'claude-3-sonnet',
250
+ apiKey: process.env.ANTHROPIC_API_KEY
251
+ };
252
+
253
+ streamDocsChatResponse(config, messages, prompt, callback, modelProvider);
254
+ ```
255
+
256
+ ### Custom Theming
257
+
258
+ ```css
259
+ /* Use CSS custom properties set by DocsThemeProvider */
260
+ .custom-element {
261
+ color: var(--docs-primary);
262
+ border-color: var(--docs-primary-light);
263
+ background-color: var(--docs-primary-dark);
264
+ }
265
+ ```
266
+
267
+ ## Requirements
268
+
269
+ - React 19+
270
+ - TypeScript 5.6+
271
+ - Node.js 18+
272
+
273
+ ## License
274
+
275
+ MIT
276
+
277
+ ## Contributing
278
+
279
+ Contributions welcome! Please read our contributing guidelines and submit pull requests to the main repository.
package/ai-chat.tsx ADDED
@@ -0,0 +1,222 @@
1
+ "use client";
2
+ import React, { useEffect, useRef, useCallback } from "react";
3
+ import { Button } from "./ui/button";
4
+ import { Input } from "./ui/input";
5
+ import { useChat } from 'ai/react';
6
+ import ReactMarkdown from 'react-markdown';
7
+ import { CodeBlock } from "./mdx/code-block";
8
+ import { ReactDocsConfig } from "./config";
9
+ import { useDocsColors } from "./theme-context";
10
+
11
+ interface Message {
12
+ role: 'user' | 'assistant' | 'system' | 'data';
13
+ content: string;
14
+ id?: string;
15
+ }
16
+
17
+ const MemoizedMarkdown = React.memo(({ content }: { content: string }) => (
18
+ <ReactMarkdown
19
+ className="w-full [&_pre]:max-w-full [&_pre]:overflow-x-auto [&_p]:leading-relaxed"
20
+ components={{
21
+ code({ node, className, children, ...props }) {
22
+ const match = /language-(\w+)/.exec(className || '');
23
+ if (match) {
24
+ const codeContent = Array.isArray(children)
25
+ ? children.join('')
26
+ : String(children);
27
+
28
+ return (
29
+ <div className="max-w-full overflow-auto">
30
+ <CodeBlock
31
+ {...props}
32
+ className={className}
33
+ >
34
+ {codeContent}
35
+ </CodeBlock>
36
+ </div>
37
+ );
38
+ }
39
+ return (
40
+ <code {...props} className="bg-gray-800/50 px-1.5 py-0.5 rounded text-sm font-mono">
41
+ {children}
42
+ </code>
43
+ );
44
+ },
45
+ }}
46
+ >
47
+ {content}
48
+ </ReactMarkdown>
49
+ ));
50
+
51
+ MemoizedMarkdown.displayName = 'MemoizedMarkdown';
52
+
53
+ const Message = React.memo(({ message }: { message: Message }) => (
54
+ <div className="rounded-lg bg-gray-800/50 p-4">
55
+ <div className="flex gap-3 items-start">
56
+ <div className={`p-2 rounded-md ${message.role === 'assistant'
57
+ ? 'bg-blue-500/10 text-blue-400'
58
+ : 'bg-gray-700/50 text-gray-400'
59
+ } mt-0.5`}>
60
+ {message.role === 'assistant' ? (
61
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
62
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
63
+ </svg>
64
+ ) : (
65
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
66
+ <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
67
+ <circle cx="12" cy="7" r="4" />
68
+ </svg>
69
+ )}
70
+ </div>
71
+ <div className="flex-1 space-y-2 min-w-0">
72
+ <div className="text-sm text-white leading-relaxed">
73
+ <MemoizedMarkdown content={message.content} />
74
+ </div>
75
+ </div>
76
+ </div>
77
+ </div>
78
+ ));
79
+
80
+ Message.displayName = 'Message';
81
+
82
+ export const AIChatOption = React.memo(({ query, onClick }: { query: string; onClick: () => void }) => {
83
+ const colors = useDocsColors();
84
+
85
+ return (
86
+ <button
87
+ className="block w-full text-left p-4 rounded-lg hover:bg-gray-800/50 transition-colors border border-gray-800"
88
+ onClick={onClick}
89
+ >
90
+ <div className="flex items-center gap-3">
91
+ <div
92
+ className="p-2 rounded-md"
93
+ style={{
94
+ backgroundColor: `${colors.primary}10`,
95
+ color: colors.primary,
96
+ }}
97
+ >
98
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
99
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
100
+ </svg>
101
+ </div>
102
+ <div>
103
+ <h3 className="text-sm font-medium text-white mb-1">Ask AI (Experimental)</h3>
104
+ <p className="text-sm text-gray-400">&quot;{query}&quot;</p>
105
+ </div>
106
+ </div>
107
+ </button>
108
+ );
109
+ });
110
+
111
+ AIChatOption.displayName = 'AIChatOption';
112
+
113
+ export function AIChat({ query, onBack, config }: { query: string; onBack: () => void; config: ReactDocsConfig }) {
114
+ const colors = useDocsColors();
115
+ const { messages, input, handleInputChange, handleSubmit, isLoading, error } = useChat({
116
+ initialMessages: [],
117
+ api: config.aiChatApiPath,
118
+ id: query,
119
+ initialInput: query,
120
+ });
121
+
122
+ const messagesEndRef = useRef<HTMLDivElement>(null);
123
+ const hasSubmittedInitialMessage = useRef(false);
124
+
125
+ const scrollToBottom = useCallback(() => {
126
+ if (messagesEndRef.current) {
127
+ const behavior = messages.length <= 2 ? "auto" : "smooth";
128
+ messagesEndRef.current.scrollIntoView({ behavior });
129
+ }
130
+ }, [messages.length]);
131
+
132
+ useEffect(() => {
133
+ scrollToBottom();
134
+ }, [scrollToBottom]);
135
+
136
+ useEffect(() => {
137
+ if (!hasSubmittedInitialMessage.current) {
138
+ const event = new Event('submit');
139
+ Object.defineProperty(event, 'target', { value: { value: query } });
140
+ handleSubmit(event as any);
141
+ hasSubmittedInitialMessage.current = true;
142
+ }
143
+ }, [query, handleSubmit]);
144
+
145
+ useEffect(() => {
146
+ if (error) {
147
+ console.error('Chat API Error:', error);
148
+ }
149
+ }, [error]);
150
+
151
+ return (
152
+ <div className="space-y-4">
153
+ <div className="flex items-center gap-2">
154
+ <button
155
+ onClick={onBack}
156
+ className="p-1 hover:bg-gray-800 rounded-md text-gray-400 hover:text-white transition-colors"
157
+ >
158
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
159
+ <path d="M19 12H5M12 19l-7-7 7-7" />
160
+ </svg>
161
+ </button>
162
+ <h3 className="text-sm font-medium text-white">Ask AI (Experimental)</h3>
163
+ </div>
164
+
165
+ <div className="space-y-4 max-h-[50vh] overflow-y-auto">
166
+ {error && (
167
+ <div className="rounded-lg bg-red-900/50 border border-red-900 p-4">
168
+ <div className="text-sm text-red-400">
169
+ Error: Failed to send message. Please try again.
170
+ </div>
171
+ </div>
172
+ )}
173
+ {messages.map((message) => (
174
+ <Message key={message.id} message={message} />
175
+ ))}
176
+ {isLoading && (
177
+ <div className="rounded-lg bg-gray-800/50 p-4">
178
+ <div className="flex gap-3 items-start">
179
+ <div className="p-2 rounded-md bg-blue-500/10 text-blue-400 mt-0.5">
180
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
181
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
182
+ </svg>
183
+ </div>
184
+ <div className="flex-1">
185
+ <div className="flex items-center gap-2 text-sm text-white">
186
+ <div className="animate-pulse">Thinking</div>
187
+ <div className="flex gap-1">
188
+ <span className="animate-bounce">.</span>
189
+ <span className="animate-bounce" style={{ animationDelay: "0.2s" }}>.</span>
190
+ <span className="animate-bounce" style={{ animationDelay: "0.4s" }}>.</span>
191
+ </div>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ )}
197
+ <div ref={messagesEndRef} />
198
+ </div>
199
+
200
+ <form onSubmit={handleSubmit} className="relative mt-4">
201
+ <Input
202
+ value={input}
203
+ onChange={handleInputChange}
204
+ placeholder="Ask a follow-up question..."
205
+ className="w-full bg-gray-800/50 border-gray-700"
206
+ disabled={isLoading}
207
+ />
208
+ <Button
209
+ type="submit"
210
+ disabled={isLoading || !input.trim()}
211
+ className="absolute right-1 top-1 h-8"
212
+ style={{
213
+ backgroundColor: colors.primary,
214
+ '--tw-bg-opacity': '1',
215
+ } as React.CSSProperties}
216
+ >
217
+ Send
218
+ </Button>
219
+ </form>
220
+ </div>
221
+ );
222
+ }
package/chat-api.ts ADDED
@@ -0,0 +1,90 @@
1
+ import { createGroq } from '@ai-sdk/groq';
2
+ import { createAnthropic } from '@ai-sdk/anthropic';
3
+ import { createOpenAI } from '@ai-sdk/openai';
4
+ import { streamText } from 'ai';
5
+ import { getAllDocsContent } from './mdx';
6
+ import { ReactDocsConfig } from './config';
7
+
8
+ export interface ModelProvider {
9
+ providerType: 'groq' | 'anthropic' | 'openai';
10
+ model?: string;
11
+ baseURL?: string;
12
+ apiKey?: string;
13
+ }
14
+
15
+ export interface Message {
16
+ role: 'user' | 'assistant' | 'system' | 'data';
17
+ content: string;
18
+ }
19
+
20
+ export interface FinishResult {
21
+ text: string;
22
+ }
23
+
24
+ export async function streamDocsChatResponse(
25
+ config: ReactDocsConfig,
26
+ messages: Message[],
27
+ systemPrompt?: string,
28
+ onFinishCallback?: (result: FinishResult) => Promise<void>,
29
+ modelProvider?: ModelProvider
30
+ ) {
31
+ // Default to groq if no provider specified
32
+ const provider = modelProvider || {
33
+ providerType: 'groq',
34
+ model: 'llama-3.3-70b-versatile'
35
+ };
36
+
37
+ // Create the appropriate model based on provider type
38
+ let model;
39
+ switch (provider.providerType) {
40
+ case 'anthropic':
41
+ const anthropicProvider = createAnthropic({
42
+ baseURL: provider.baseURL,
43
+ apiKey: provider.apiKey,
44
+ });
45
+ model = anthropicProvider(provider.model || 'claude-3-5-sonnet-20241022');
46
+ break;
47
+ case 'openai':
48
+ const openaiProvider = createOpenAI({
49
+ baseURL: provider.baseURL,
50
+ apiKey: provider.apiKey,
51
+ });
52
+ model = openaiProvider(provider.model || 'gpt-4o');
53
+ break;
54
+ case 'groq':
55
+ default:
56
+ const groqProvider = createGroq({
57
+ baseURL: provider.baseURL,
58
+ apiKey: provider.apiKey,
59
+ });
60
+ model = groqProvider(provider.model || 'llama-3.3-70b-versatile');
61
+ break;
62
+ }
63
+
64
+ const docsSystemPrompt = systemPrompt || `You are a helpful assistant for the provided documentation knowledge base.
65
+ Based on user questions you should be able to help them by providing answers based on the knowledge base only.
66
+ Keep your responses concise and focused.`;
67
+
68
+ const docsContent = getAllDocsContent(config);
69
+
70
+ const stream = streamText({
71
+ // Type assertion needed due to AI SDK version compatibility between LanguageModelV1/V2
72
+ model: model as Parameters<typeof streamText>[0]['model'],
73
+ onFinish: async (result) => {
74
+ if (onFinishCallback) {
75
+ await onFinishCallback({ text: result.text });
76
+ }
77
+ },
78
+ messages: [
79
+ {
80
+ role: 'system',
81
+ content: `${docsSystemPrompt}
82
+ Documentation Knowledge Base:
83
+ ${docsContent}`,
84
+ },
85
+ ...messages,
86
+ ],
87
+ });
88
+
89
+ return stream.toDataStreamResponse();
90
+ }
package/cn.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
7
+
8
+ export function slugify(str: string) {
9
+ return String(str)
10
+ .toLowerCase()
11
+ .trim()
12
+ .replace(/[^\w\s-]/g, '')
13
+ .replace(/[\s_-]+/g, '-')
14
+ .replace(/^-+|-+$/g, '');
15
+ }
package/config.ts ADDED
@@ -0,0 +1,29 @@
1
+ export interface ReactDocsConfig {
2
+ basePath: string;
3
+ contentPath: string;
4
+ searchApiPath: string;
5
+ aiChatApiPath: string;
6
+ }
7
+
8
+ export interface ReactDocsConfigOptions {
9
+ basePath?: string;
10
+ contentPath?: string;
11
+ searchApiPath?: string;
12
+ aiChatApiPath?: string;
13
+ }
14
+
15
+ const DEFAULT_CONFIG: ReactDocsConfig = {
16
+ basePath: "/docs",
17
+ contentPath: "content/docs",
18
+ searchApiPath: "/api/docs/search-index",
19
+ aiChatApiPath: "/api/docs/chat",
20
+ };
21
+
22
+ export function createReactDocsConfig(options: ReactDocsConfigOptions = {}): ReactDocsConfig {
23
+ return {
24
+ basePath: options.basePath ?? DEFAULT_CONFIG.basePath,
25
+ contentPath: options.contentPath ?? DEFAULT_CONFIG.contentPath,
26
+ searchApiPath: options.searchApiPath ?? DEFAULT_CONFIG.searchApiPath,
27
+ aiChatApiPath: options.aiChatApiPath ?? DEFAULT_CONFIG.aiChatApiPath,
28
+ };
29
+ }
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import { ReactDocsConfig } from "./config";
3
+ export declare const AIChatOption: React.MemoExoticComponent<({ query, onClick }: {
4
+ query: string;
5
+ onClick: () => void;
6
+ }) => import("react/jsx-runtime").JSX.Element>;
7
+ export declare function AIChat({ query, onBack, config }: {
8
+ query: string;
9
+ onBack: () => void;
10
+ config: ReactDocsConfig;
11
+ }): import("react/jsx-runtime").JSX.Element;
12
+ //# sourceMappingURL=ai-chat.d.ts.map