@doderasoftware/restify-ai 0.1.0-beta.1
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.
- package/LICENSE +21 -0
- package/README.md +514 -0
- package/dist/components/AiAvatar.vue.d.ts +27 -0
- package/dist/components/AiAvatar.vue.d.ts.map +1 -0
- package/dist/components/AiChatDrawer.vue.d.ts +148 -0
- package/dist/components/AiChatDrawer.vue.d.ts.map +1 -0
- package/dist/components/AiEmptyState.vue.d.ts +36 -0
- package/dist/components/AiEmptyState.vue.d.ts.map +1 -0
- package/dist/components/ChatInput.vue.d.ts +110 -0
- package/dist/components/ChatInput.vue.d.ts.map +1 -0
- package/dist/components/ChatMessage.vue.d.ts +44 -0
- package/dist/components/ChatMessage.vue.d.ts.map +1 -0
- package/dist/components/ChatMessageActions.vue.d.ts +33 -0
- package/dist/components/ChatMessageActions.vue.d.ts.map +1 -0
- package/dist/components/MentionList.vue.d.ts +58 -0
- package/dist/components/MentionList.vue.d.ts.map +1 -0
- package/dist/components/UserAvatar.vue.d.ts +27 -0
- package/dist/components/UserAvatar.vue.d.ts.map +1 -0
- package/dist/components/drawer/ConfirmDialog.vue.d.ts +47 -0
- package/dist/components/drawer/ConfirmDialog.vue.d.ts.map +1 -0
- package/dist/components/drawer/DrawerHeader.vue.d.ts +46 -0
- package/dist/components/drawer/DrawerHeader.vue.d.ts.map +1 -0
- package/dist/components/drawer/DrawerMessageList.vue.d.ts +44 -0
- package/dist/components/drawer/DrawerMessageList.vue.d.ts.map +1 -0
- package/dist/components/drawer/SetupGuide.vue.d.ts +19 -0
- package/dist/components/drawer/SetupGuide.vue.d.ts.map +1 -0
- package/dist/components/index.d.ts +9 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/input/AttachmentsPreview.vue.d.ts +30 -0
- package/dist/components/input/AttachmentsPreview.vue.d.ts.map +1 -0
- package/dist/components/input/InputActions.vue.d.ts +28 -0
- package/dist/components/input/InputActions.vue.d.ts.map +1 -0
- package/dist/components/input/SuggestionsDropdown.vue.d.ts +32 -0
- package/dist/components/input/SuggestionsDropdown.vue.d.ts.map +1 -0
- package/dist/composables/index.d.ts +12 -0
- package/dist/composables/index.d.ts.map +1 -0
- package/dist/composables/useAiContext.d.ts +18 -0
- package/dist/composables/useAiContext.d.ts.map +1 -0
- package/dist/composables/useAiSuggestions.d.ts +11 -0
- package/dist/composables/useAiSuggestions.d.ts.map +1 -0
- package/dist/composables/useChatErrorHandling.d.ts +14 -0
- package/dist/composables/useChatErrorHandling.d.ts.map +1 -0
- package/dist/composables/useChatInput.d.ts +108 -0
- package/dist/composables/useChatInput.d.ts.map +1 -0
- package/dist/composables/useChatMarkdown.d.ts +10 -0
- package/dist/composables/useChatMarkdown.d.ts.map +1 -0
- package/dist/composables/useChatScroll.d.ts +10 -0
- package/dist/composables/useChatScroll.d.ts.map +1 -0
- package/dist/composables/useHistoryLimit.d.ts +37 -0
- package/dist/composables/useHistoryLimit.d.ts.map +1 -0
- package/dist/composables/useKeyboardShortcut.d.ts +14 -0
- package/dist/composables/useKeyboardShortcut.d.ts.map +1 -0
- package/dist/composables/useLoadingText.d.ts +12 -0
- package/dist/composables/useLoadingText.d.ts.map +1 -0
- package/dist/composables/useMentionParsing.d.ts +67 -0
- package/dist/composables/useMentionParsing.d.ts.map +1 -0
- package/dist/composables/usePageAiContext.d.ts +24 -0
- package/dist/composables/usePageAiContext.d.ts.map +1 -0
- package/dist/composables/useSuggestions.d.ts +2 -0
- package/dist/composables/useSuggestions.d.ts.map +1 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/restify-ai.js +5425 -0
- package/dist/restify-ai.umd.cjs +76 -0
- package/dist/store.d.ts +247 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/style.css +1 -0
- package/dist/suggestions/index.d.ts +24 -0
- package/dist/suggestions/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +601 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +119 -0
- package/tailwind.config.cjs +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dodera Software
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
# @doderasoftware/restify-ai
|
|
2
|
+
|
|
3
|
+
> 🤖 A fully customizable Vue 3 AI chatbot component library with Laravel Restify integration
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@doderasoftware/restify-ai)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://vuejs.org/)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## ✨ Features
|
|
12
|
+
|
|
13
|
+
| Feature | Description |
|
|
14
|
+
|---------|-------------|
|
|
15
|
+
| 🔌 **Laravel Restify** | Built for seamless Laravel Restify AI endpoints |
|
|
16
|
+
| 📡 **SSE Streaming** | Real-time streaming responses with Server-Sent Events |
|
|
17
|
+
| 📎 **File Attachments** | Built-in file upload with progress & preview |
|
|
18
|
+
| 💬 **@Mentions** | Pluggable mention providers (employees, projects, etc.) |
|
|
19
|
+
| 💡 **Smart Suggestions** | Route-aware suggestion system |
|
|
20
|
+
| 🎨 **Fully Customizable** | UI classes, texts, slots, themes |
|
|
21
|
+
| ⌨️ **Keyboard Shortcuts** | Configurable shortcuts (e.g., \`Cmd+G\`) |
|
|
22
|
+
| 🔄 **Auto Retry** | Configurable retry logic with exponential backoff |
|
|
23
|
+
| 💾 **Session Persistence** | Chat history survives page refresh |
|
|
24
|
+
| 🌙 **Dark Mode** | Full dark mode support out of the box |
|
|
25
|
+
| 📦 **Tree-shakable** | Import only what you need |
|
|
26
|
+
| 🎯 **TypeScript** | Full TypeScript support |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 📦 Installation
|
|
31
|
+
|
|
32
|
+
\`\`\`bash
|
|
33
|
+
npm install @doderasoftware/restify-ai
|
|
34
|
+
# or
|
|
35
|
+
pnpm add @doderasoftware/restify-ai
|
|
36
|
+
\`\`\`
|
|
37
|
+
|
|
38
|
+
**Peer Dependencies:** \`vue ^3.4\`, \`pinia ^2.1\`
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 🚀 Quick Start
|
|
43
|
+
|
|
44
|
+
\`\`\`typescript
|
|
45
|
+
// main.ts
|
|
46
|
+
import { createApp } from 'vue'
|
|
47
|
+
import { createPinia } from 'pinia'
|
|
48
|
+
import { RestifyAiPlugin } from '@doderasoftware/restify-ai'
|
|
49
|
+
import '@doderasoftware/restify-ai/styles'
|
|
50
|
+
|
|
51
|
+
const app = createApp(App)
|
|
52
|
+
app.use(createPinia())
|
|
53
|
+
|
|
54
|
+
app.use(RestifyAiPlugin, {
|
|
55
|
+
endpoints: {
|
|
56
|
+
ask: '/api/ai/ask', // Required - SSE streaming endpoint
|
|
57
|
+
quota: '/api/ai/quota', // Optional - quota endpoint
|
|
58
|
+
uploadFile: '/api/ai/upload', // Optional - file upload
|
|
59
|
+
},
|
|
60
|
+
getAuthToken: () => localStorage.getItem('token'),
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
app.mount('#app')
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
66
|
+
\`\`\`vue
|
|
67
|
+
<!-- App.vue -->
|
|
68
|
+
<template>
|
|
69
|
+
<AiChatDrawer v-model="showChat" />
|
|
70
|
+
<button @click="showChat = true">Open AI Chat</button>
|
|
71
|
+
</template>
|
|
72
|
+
|
|
73
|
+
<script setup>
|
|
74
|
+
import { ref } from 'vue'
|
|
75
|
+
import { AiChatDrawer } from '@doderasoftware/restify-ai'
|
|
76
|
+
|
|
77
|
+
const showChat = ref(false)
|
|
78
|
+
</script>
|
|
79
|
+
\`\`\`
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## ⚙️ Plugin Configuration
|
|
84
|
+
|
|
85
|
+
### Required Options
|
|
86
|
+
|
|
87
|
+
| Option | Type | Description |
|
|
88
|
+
|--------|------|-------------|
|
|
89
|
+
| \`endpoints.ask\` | \`string\` | SSE streaming endpoint |
|
|
90
|
+
| \`getAuthToken\` | \`() => string \| Promise<string>\` | Auth token getter |
|
|
91
|
+
|
|
92
|
+
### API Configuration
|
|
93
|
+
|
|
94
|
+
\`\`\`typescript
|
|
95
|
+
{
|
|
96
|
+
baseUrl: 'https://api.example.com',
|
|
97
|
+
endpoints: {
|
|
98
|
+
ask: '/api/ai/ask',
|
|
99
|
+
quota: '/api/ai/quota',
|
|
100
|
+
uploadFile: '/api/ai/upload',
|
|
101
|
+
},
|
|
102
|
+
getAuthToken: () => authStore.token,
|
|
103
|
+
getCustomHeaders: () => ({
|
|
104
|
+
'X-CSRF-TOKEN': csrfToken,
|
|
105
|
+
'X-App-Version': '1.0.0',
|
|
106
|
+
}),
|
|
107
|
+
}
|
|
108
|
+
\`\`\`
|
|
109
|
+
|
|
110
|
+
### Request Customization
|
|
111
|
+
|
|
112
|
+
\`\`\`typescript
|
|
113
|
+
{
|
|
114
|
+
// Modify request payload before sending
|
|
115
|
+
buildRequest: (payload) => ({
|
|
116
|
+
...payload,
|
|
117
|
+
context: { page: 'dashboard' },
|
|
118
|
+
}),
|
|
119
|
+
|
|
120
|
+
// Custom stream parser (default: OpenAI format)
|
|
121
|
+
parseStreamContent: (data) => JSON.parse(data).content,
|
|
122
|
+
|
|
123
|
+
// Request/response interceptors
|
|
124
|
+
requestInterceptor: (url, options) => options,
|
|
125
|
+
responseInterceptor: (response) => response,
|
|
126
|
+
}
|
|
127
|
+
\`\`\`
|
|
128
|
+
|
|
129
|
+
### Retry Configuration
|
|
130
|
+
|
|
131
|
+
\`\`\`typescript
|
|
132
|
+
{
|
|
133
|
+
retry: {
|
|
134
|
+
maxRetries: 3,
|
|
135
|
+
retryDelay: 1000, // ms, multiplied by attempt
|
|
136
|
+
shouldRetry: (error, attempt) => error.status >= 500,
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
\`\`\`
|
|
140
|
+
|
|
141
|
+
### Providers
|
|
142
|
+
|
|
143
|
+
\`\`\`typescript
|
|
144
|
+
{
|
|
145
|
+
// @Mention providers
|
|
146
|
+
mentionProviders: [
|
|
147
|
+
{
|
|
148
|
+
type: 'employee',
|
|
149
|
+
label: 'Employees',
|
|
150
|
+
priority: 10,
|
|
151
|
+
search: async (query) => api.searchEmployees(query),
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
|
|
155
|
+
// Route-aware suggestions
|
|
156
|
+
suggestionProviders: [
|
|
157
|
+
{
|
|
158
|
+
id: 'dashboard',
|
|
159
|
+
routes: ['/dashboard', '/analytics'],
|
|
160
|
+
getSuggestions: (context) => [...],
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
|
|
164
|
+
// Default suggestions for empty state
|
|
165
|
+
defaultSuggestions: [
|
|
166
|
+
{ id: '1', title: 'How can you help?', prompt: 'What can you do?' },
|
|
167
|
+
],
|
|
168
|
+
}
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
### Limits & Storage
|
|
172
|
+
|
|
173
|
+
\`\`\`typescript
|
|
174
|
+
{
|
|
175
|
+
chatHistoryLimit: 15, // Max messages
|
|
176
|
+
maxAttachments: 5, // Max files per message
|
|
177
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
178
|
+
acceptedFileTypes: 'image/*,.pdf,.txt',
|
|
179
|
+
chatHistoryKey: 'my_chat_history', // sessionStorage key
|
|
180
|
+
drawerStateKey: 'my_drawer_state', // localStorage key
|
|
181
|
+
}
|
|
182
|
+
\`\`\`
|
|
183
|
+
|
|
184
|
+
### Features
|
|
185
|
+
|
|
186
|
+
\`\`\`typescript
|
|
187
|
+
{
|
|
188
|
+
keyboardShortcut: 'cmd+g', // null to disable
|
|
189
|
+
enableSupportMode: true, // Support request toggle
|
|
190
|
+
}
|
|
191
|
+
\`\`\`
|
|
192
|
+
|
|
193
|
+
### Custom Components
|
|
194
|
+
|
|
195
|
+
\`\`\`typescript
|
|
196
|
+
{
|
|
197
|
+
assistantAvatar: MyAvatarComponent,
|
|
198
|
+
userAvatar: UserAvatarComponent,
|
|
199
|
+
}
|
|
200
|
+
\`\`\`
|
|
201
|
+
|
|
202
|
+
### Lifecycle Callbacks
|
|
203
|
+
|
|
204
|
+
\`\`\`typescript
|
|
205
|
+
{
|
|
206
|
+
onError: (error) => console.error(error),
|
|
207
|
+
onQuotaFetched: (quota) => console.log(quota),
|
|
208
|
+
onMessageSent: (message) => analytics.track('message_sent'),
|
|
209
|
+
onResponseReceived: (message) => console.log(message),
|
|
210
|
+
onDrawerToggle: (isOpen) => console.log(isOpen),
|
|
211
|
+
onNewChat: () => console.log('New chat started'),
|
|
212
|
+
|
|
213
|
+
// Stream hooks
|
|
214
|
+
onStreamStart: () => console.log('Streaming...'),
|
|
215
|
+
onStreamEnd: (fullMessage) => console.log('Done'),
|
|
216
|
+
onStreamChunk: (chunk) => console.log(chunk.content),
|
|
217
|
+
beforeSend: (payload) => payload,
|
|
218
|
+
afterResponse: (message) => saveToHistory(message),
|
|
219
|
+
|
|
220
|
+
// File upload hooks
|
|
221
|
+
onFileUploadStart: (file) => console.log('Uploading', file.name),
|
|
222
|
+
onFileUploadProgress: (file, progress) => console.log(progress),
|
|
223
|
+
onFileUploadComplete: (file) => console.log('Done'),
|
|
224
|
+
onFileUploadError: (file, error) => console.error(error),
|
|
225
|
+
}
|
|
226
|
+
\`\`\`
|
|
227
|
+
|
|
228
|
+
### Labels / i18n
|
|
229
|
+
|
|
230
|
+
\`\`\`typescript
|
|
231
|
+
{
|
|
232
|
+
labels: {
|
|
233
|
+
aiName: 'My AI Assistant',
|
|
234
|
+
inputPlaceholder: 'Type your message...',
|
|
235
|
+
emptyStateTitle: 'How can I help?',
|
|
236
|
+
// 40+ customizable labels
|
|
237
|
+
},
|
|
238
|
+
translate: (key, params) => i18n.t(key, params),
|
|
239
|
+
can: (permission) => user.hasPermission(permission),
|
|
240
|
+
}
|
|
241
|
+
\`\`\`
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## 🧩 Components
|
|
246
|
+
|
|
247
|
+
### \`<AiChatDrawer>\`
|
|
248
|
+
|
|
249
|
+
Main chat drawer component with all features.
|
|
250
|
+
|
|
251
|
+
#### Props
|
|
252
|
+
|
|
253
|
+
| Prop | Type | Default | Description |
|
|
254
|
+
|------|------|---------|-------------|
|
|
255
|
+
| \`v-model\` | \`boolean\` | - | Drawer visibility |
|
|
256
|
+
| \`width\` | \`string\` | \`'600px'\` | Drawer width |
|
|
257
|
+
| \`fullscreenWidth\` | \`string\` | \`'90vw'\` | Fullscreen width |
|
|
258
|
+
| \`position\` | \`'left' \| 'right'\` | \`'right'\` | Drawer position |
|
|
259
|
+
| \`showBackdrop\` | \`boolean\` | \`false\` | Show backdrop overlay |
|
|
260
|
+
| \`closeOnBackdropClick\` | \`boolean\` | \`false\` | Close on backdrop click |
|
|
261
|
+
| \`closeOnEscape\` | \`boolean\` | \`true\` | Close on Escape key |
|
|
262
|
+
| \`showQuota\` | \`boolean\` | \`true\` | Show quota display |
|
|
263
|
+
| \`showFullscreenToggle\` | \`boolean\` | \`true\` | Show fullscreen button |
|
|
264
|
+
| \`showMinimizeButton\` | \`boolean\` | \`true\` | Show minimize button |
|
|
265
|
+
| \`showCloseButton\` | \`boolean\` | \`true\` | Show close button |
|
|
266
|
+
| \`showNewChatButton\` | \`boolean\` | \`true\` | Show new chat button |
|
|
267
|
+
| \`confirmClose\` | \`boolean\` | \`true\` | Confirm before closing |
|
|
268
|
+
| \`ui\` | \`AiChatDrawerUI\` | - | Custom CSS classes |
|
|
269
|
+
| \`texts\` | \`AiChatDrawerTexts\` | - | Custom text labels |
|
|
270
|
+
| \`historyLimit\` | \`HistoryLimitConfig\` | - | History limit config |
|
|
271
|
+
| \`loadingText\` | \`LoadingTextConfig\` | - | Dynamic loading text |
|
|
272
|
+
|
|
273
|
+
#### Events
|
|
274
|
+
|
|
275
|
+
| Event | Payload | Description |
|
|
276
|
+
|-------|---------|-------------|
|
|
277
|
+
| \`close\` | - | Drawer closed |
|
|
278
|
+
| \`contact-support\` | - | Support mode triggered |
|
|
279
|
+
| \`new-chat\` | - | New chat started |
|
|
280
|
+
|
|
281
|
+
#### Slots
|
|
282
|
+
|
|
283
|
+
| Slot | Props | Description |
|
|
284
|
+
|------|-------|-------------|
|
|
285
|
+
| \`header\` | \`HeaderSlotProps\` | Custom header |
|
|
286
|
+
| \`empty-state\` | \`{ suggestions, onClick }\` | Custom empty state |
|
|
287
|
+
| \`message\` | \`MessageSlotProps\` | Custom message rendering |
|
|
288
|
+
| \`input\` | \`InputSlotProps\` | Custom input |
|
|
289
|
+
| \`quota\` | \`{ quota }\` | Custom quota display |
|
|
290
|
+
| \`setup\` | - | Custom setup guide |
|
|
291
|
+
| \`context-link\` | - | Link above input |
|
|
292
|
+
|
|
293
|
+
### Other Components
|
|
294
|
+
|
|
295
|
+
| Component | Description |
|
|
296
|
+
|-----------|-------------|
|
|
297
|
+
| \`<ChatInput>\` | Message input with attachments & mentions |
|
|
298
|
+
| \`<ChatMessage>\` | Single message display |
|
|
299
|
+
| \`<AiEmptyState>\` | Empty state with suggestions |
|
|
300
|
+
| \`<MentionList>\` | @mention dropdown |
|
|
301
|
+
| \`<AiAvatar>\` | AI avatar icon |
|
|
302
|
+
| \`<UserAvatar>\` | User avatar icon |
|
|
303
|
+
| \`<ChatMessageActions>\` | Copy/action buttons |
|
|
304
|
+
|
|
305
|
+
All components accept \`:ui\` and \`:texts\` props for full customization.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## 🎨 UI Customization
|
|
310
|
+
|
|
311
|
+
Every component accepts a \`:ui\` prop for CSS class overrides:
|
|
312
|
+
|
|
313
|
+
\`\`\`vue
|
|
314
|
+
<AiChatDrawer
|
|
315
|
+
:ui="{
|
|
316
|
+
drawer: 'my-drawer-class',
|
|
317
|
+
header: 'my-header-class',
|
|
318
|
+
body: 'my-body-class',
|
|
319
|
+
}"
|
|
320
|
+
:texts="{
|
|
321
|
+
title: 'My AI',
|
|
322
|
+
placeholder: 'Ask anything...',
|
|
323
|
+
}"
|
|
324
|
+
/>
|
|
325
|
+
\`\`\`
|
|
326
|
+
|
|
327
|
+
### Available UI Props
|
|
328
|
+
|
|
329
|
+
- \`AiChatDrawerUI\` - backdrop, drawer, panel, header, body, etc.
|
|
330
|
+
- \`ChatInputUI\` - root, textarea, sendButton, attachButton, etc.
|
|
331
|
+
- \`ChatMessageUI\` - userBubble, assistantBubble, loadingDots, etc.
|
|
332
|
+
- \`AiEmptyStateUI\` - grid, suggestionCard, title, etc.
|
|
333
|
+
- \`MentionListUI\` - item, itemSelected, groupHeader, etc.
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## 📚 Composables
|
|
338
|
+
|
|
339
|
+
\`\`\`typescript
|
|
340
|
+
import {
|
|
341
|
+
useRestifyAiStore, // Pinia store
|
|
342
|
+
useAiSuggestions, // Suggestions management
|
|
343
|
+
useAiContext, // Page context
|
|
344
|
+
usePageAiContext, // Route-based context
|
|
345
|
+
useKeyboardShortcut, // Custom shortcuts
|
|
346
|
+
useAiDrawerShortcut, // Drawer toggle shortcut
|
|
347
|
+
useMentionParsing, // Parse @mentions
|
|
348
|
+
useChatMarkdown, // Markdown rendering
|
|
349
|
+
useChatScroll, // Auto-scroll
|
|
350
|
+
useChatErrorHandling, // Error management
|
|
351
|
+
useLoadingText, // Dynamic loading messages
|
|
352
|
+
useHistoryLimit, // History limit dialogs
|
|
353
|
+
} from '@doderasoftware/restify-ai'
|
|
354
|
+
\`\`\`
|
|
355
|
+
|
|
356
|
+
### Store Actions
|
|
357
|
+
|
|
358
|
+
\`\`\`typescript
|
|
359
|
+
const store = useRestifyAiStore()
|
|
360
|
+
|
|
361
|
+
store.askQuestion(question, attachments, mentions)
|
|
362
|
+
store.cancelRequest()
|
|
363
|
+
store.retry()
|
|
364
|
+
store.clearChatHistory()
|
|
365
|
+
store.clearError()
|
|
366
|
+
store.fetchQuota()
|
|
367
|
+
store.toggleSupportMode()
|
|
368
|
+
\`\`\`
|
|
369
|
+
|
|
370
|
+
### Store State
|
|
371
|
+
|
|
372
|
+
\`\`\`typescript
|
|
373
|
+
store.chatHistory // ChatMessage[]
|
|
374
|
+
store.sending // boolean
|
|
375
|
+
store.error // ChatError
|
|
376
|
+
store.quota // ChatQuota
|
|
377
|
+
store.showChat // boolean
|
|
378
|
+
store.isFullscreen // boolean
|
|
379
|
+
store.supportRequestMode // boolean
|
|
380
|
+
\`\`\`
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## 🔧 Advanced Features
|
|
385
|
+
|
|
386
|
+
### History Limit Dialog
|
|
387
|
+
|
|
388
|
+
\`\`\`vue
|
|
389
|
+
<AiChatDrawer
|
|
390
|
+
:history-limit="{
|
|
391
|
+
limit: 20,
|
|
392
|
+
showWarningAt: 3,
|
|
393
|
+
warningMessage: 'Almost at limit!',
|
|
394
|
+
limitMessage: 'Start a new chat to continue.',
|
|
395
|
+
}"
|
|
396
|
+
/>
|
|
397
|
+
\`\`\`
|
|
398
|
+
|
|
399
|
+
### Dynamic Loading Text
|
|
400
|
+
|
|
401
|
+
\`\`\`vue
|
|
402
|
+
<AiChatDrawer
|
|
403
|
+
:loading-text="{
|
|
404
|
+
messages: ['Thinking...', 'Analyzing...', 'Almost done...'],
|
|
405
|
+
intervals: [0, 2000, 4000],
|
|
406
|
+
}"
|
|
407
|
+
/>
|
|
408
|
+
\`\`\`
|
|
409
|
+
|
|
410
|
+
### Keyboard Shortcut
|
|
411
|
+
|
|
412
|
+
\`\`\`typescript
|
|
413
|
+
// Plugin config
|
|
414
|
+
{ keyboardShortcut: 'cmd+shift+a' }
|
|
415
|
+
|
|
416
|
+
// Or use composable
|
|
417
|
+
const { toggle } = useAiDrawerShortcut()
|
|
418
|
+
\`\`\`
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## 📡 Laravel Restify Backend
|
|
423
|
+
|
|
424
|
+
Expected SSE endpoint format:
|
|
425
|
+
|
|
426
|
+
\`\`\`php
|
|
427
|
+
// routes/api.php
|
|
428
|
+
Route::post('/ai/ask', [AiController::class, 'ask']);
|
|
429
|
+
Route::get('/ai/quota', [AiController::class, 'quota']);
|
|
430
|
+
\`\`\`
|
|
431
|
+
|
|
432
|
+
\`\`\`php
|
|
433
|
+
// AiController.php
|
|
434
|
+
public function ask(Request $request)
|
|
435
|
+
{
|
|
436
|
+
return response()->stream(function () use ($request) {
|
|
437
|
+
// Stream OpenAI-format chunks
|
|
438
|
+
echo "data: " . json_encode([
|
|
439
|
+
'choices' => [['delta' => ['content' => 'Hello']]]
|
|
440
|
+
]) . "\n\n";
|
|
441
|
+
ob_flush();
|
|
442
|
+
flush();
|
|
443
|
+
|
|
444
|
+
echo "data: [DONE]\n\n";
|
|
445
|
+
}, 200, [
|
|
446
|
+
'Content-Type' => 'text/event-stream',
|
|
447
|
+
'Cache-Control' => 'no-cache',
|
|
448
|
+
'X-Accel-Buffering' => 'no',
|
|
449
|
+
]);
|
|
450
|
+
}
|
|
451
|
+
\`\`\`
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## 📝 TypeScript Types
|
|
456
|
+
|
|
457
|
+
All types are exported:
|
|
458
|
+
|
|
459
|
+
\`\`\`typescript
|
|
460
|
+
import type {
|
|
461
|
+
ChatMessage,
|
|
462
|
+
ChatAttachment,
|
|
463
|
+
Mention,
|
|
464
|
+
MentionProvider,
|
|
465
|
+
SuggestionProvider,
|
|
466
|
+
AISuggestion,
|
|
467
|
+
RestifyAiConfig,
|
|
468
|
+
ChatQuota,
|
|
469
|
+
ChatError,
|
|
470
|
+
// UI types
|
|
471
|
+
AiChatDrawerUI,
|
|
472
|
+
ChatInputUI,
|
|
473
|
+
ChatMessageUI,
|
|
474
|
+
// Text types
|
|
475
|
+
AiChatDrawerTexts,
|
|
476
|
+
ChatInputTexts,
|
|
477
|
+
// Config types
|
|
478
|
+
HistoryLimitConfig,
|
|
479
|
+
LoadingTextConfig,
|
|
480
|
+
RetryConfig,
|
|
481
|
+
// Hook types
|
|
482
|
+
BeforeSendHook,
|
|
483
|
+
AfterResponseHook,
|
|
484
|
+
StreamParserFunction,
|
|
485
|
+
} from '@doderasoftware/restify-ai'
|
|
486
|
+
\`\`\`
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## 📋 Quick Reference
|
|
491
|
+
|
|
492
|
+
| Feature | Configuration |
|
|
493
|
+
|---------|---------------|
|
|
494
|
+
| SSE Streaming | Built-in, automatic |
|
|
495
|
+
| Keyboard Shortcut | \`keyboardShortcut: 'cmd+g'\` |
|
|
496
|
+
| @Mentions | \`mentionProviders: [...]\` |
|
|
497
|
+
| Route Suggestions | \`suggestionProviders: [...]\` |
|
|
498
|
+
| File Attachments | \`endpoints.uploadFile\` + \`maxAttachments\` |
|
|
499
|
+
| Support Mode | \`enableSupportMode: true\` |
|
|
500
|
+
| Custom Headers | \`getCustomHeaders: () => ({...})\` |
|
|
501
|
+
| Auth Token | \`getAuthToken: () => token\` |
|
|
502
|
+
| Base URL | \`baseUrl: 'https://api.example.com'\` |
|
|
503
|
+
| Error Handling | \`onError: (err) => {...}\` |
|
|
504
|
+
| Retry Logic | \`retry: { maxRetries: 3 }\` |
|
|
505
|
+
| UI Customization | \`:ui\` prop on all components |
|
|
506
|
+
| Text/i18n | \`:texts\` prop + \`labels\` config |
|
|
507
|
+
| History Limit | \`:history-limit\` prop |
|
|
508
|
+
| Loading Messages | \`:loading-text\` prop |
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
## 📄 License
|
|
513
|
+
|
|
514
|
+
MIT © [Dodera Software](https://github.com/doderasoftware)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AiAvatarUI } from '../types';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
/** Custom UI classes for styling */
|
|
5
|
+
ui?: AiAvatarUI;
|
|
6
|
+
}
|
|
7
|
+
declare function __VLS_template(): {
|
|
8
|
+
default?(_: {}): any;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_component: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<Props>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<Props>>> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
11
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
|
|
12
|
+
export default _default;
|
|
13
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
14
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
15
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
16
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
17
|
+
} : {
|
|
18
|
+
type: import('vue').PropType<T[K]>;
|
|
19
|
+
required: true;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
23
|
+
new (): {
|
|
24
|
+
$slots: S;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=AiAvatar.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiAvatar.vue.d.ts","sourceRoot":"","sources":["../../src/components/AiAvatar.vue"],"names":[],"mappings":"AAmBA;AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAI1C,UAAU,KAAK;IACb,oCAAoC;IACpC,EAAE,CAAC,EAAE,UAAU,CAAA;CAChB;AAOD,iBAAS,cAAc;qBA0DM,GAAG;EAK/B;AAQD,QAAA,MAAM,eAAe,mZAMnB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAAvG,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
|