ai-input-react 1.0.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/README.md +294 -0
- package/dist/index.d.mts +255 -0
- package/dist/index.d.ts +255 -0
- package/dist/index.js +633 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +628 -0
- package/dist/index.mjs.map +1 -0
- package/dist/styles.css +2 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# ai-input-react
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ai-input-react)
|
|
4
|
+
[](https://github.com/Soptik1290/ai-input/blob/main/LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/ai-input-react)
|
|
6
|
+
|
|
7
|
+
**A React input component with AI text/voice support.** Unified text and audio input with real-time waveform visualization, designed for AI-powered applications.
|
|
8
|
+
|
|
9
|
+
## Why Use This?
|
|
10
|
+
|
|
11
|
+
- 🎤 **Unified Input** – Text and audio in a single component
|
|
12
|
+
- 🌊 **Real-time Waveform** – Audio visualization during recording
|
|
13
|
+
- 🎨 **Zero Config Styling** – Prepacked CSS, no Tailwind needed
|
|
14
|
+
- 🔌 **Headless Mode** – Full control with render props
|
|
15
|
+
- ⚡ **Framework Agnostic** – Next.js, Vite, Laravel, etc.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# npm
|
|
23
|
+
npm install ai-input-react
|
|
24
|
+
|
|
25
|
+
# yarn
|
|
26
|
+
yarn add ai-input-react
|
|
27
|
+
|
|
28
|
+
# pnpm
|
|
29
|
+
pnpm add ai-input-react
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { AiInput } from 'ai-input-react'
|
|
38
|
+
import 'ai-input-react/styles.css'
|
|
39
|
+
|
|
40
|
+
function App() {
|
|
41
|
+
return (
|
|
42
|
+
<AiInput
|
|
43
|
+
send={async (input) => {
|
|
44
|
+
const res = await fetch('/api/chat', {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
body: JSON.stringify({ message: input }),
|
|
47
|
+
})
|
|
48
|
+
return res.json()
|
|
49
|
+
}}
|
|
50
|
+
onSuccess={(result) => console.log('Response:', result)}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That's it! The component includes text input with a microphone button for audio recording.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Framework Examples
|
|
61
|
+
|
|
62
|
+
<details>
|
|
63
|
+
<summary><strong>Next.js (App Router)</strong></summary>
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
// app/page.tsx
|
|
67
|
+
'use client'
|
|
68
|
+
|
|
69
|
+
import { AiInput } from 'ai-input-react'
|
|
70
|
+
import 'ai-input-react/styles.css'
|
|
71
|
+
|
|
72
|
+
export default function Home() {
|
|
73
|
+
return (
|
|
74
|
+
<AiInput
|
|
75
|
+
send={async (input) => {
|
|
76
|
+
const res = await fetch('/api/chat', {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
body: JSON.stringify({ message: input }),
|
|
79
|
+
})
|
|
80
|
+
return res.json()
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
</details>
|
|
87
|
+
|
|
88
|
+
<details>
|
|
89
|
+
<summary><strong>Laravel + Inertia</strong></summary>
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
// resources/js/Pages/Chat.tsx
|
|
93
|
+
import { AiInput } from 'ai-input-react'
|
|
94
|
+
import 'ai-input-react/styles.css'
|
|
95
|
+
|
|
96
|
+
export default function Chat({ csrfToken }: { csrfToken: string }) {
|
|
97
|
+
return (
|
|
98
|
+
<AiInput
|
|
99
|
+
send={async (input) => {
|
|
100
|
+
const res = await fetch('/api/chat', {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: {
|
|
103
|
+
'X-CSRF-TOKEN': csrfToken,
|
|
104
|
+
'Content-Type': 'application/json',
|
|
105
|
+
},
|
|
106
|
+
body: JSON.stringify({ message: input }),
|
|
107
|
+
})
|
|
108
|
+
return res.json()
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
</details>
|
|
115
|
+
|
|
116
|
+
<details>
|
|
117
|
+
<summary><strong>Vite</strong></summary>
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
// src/App.tsx
|
|
121
|
+
import { AiInput } from 'ai-input-react'
|
|
122
|
+
import 'ai-input-react/styles.css'
|
|
123
|
+
|
|
124
|
+
export default function App() {
|
|
125
|
+
return (
|
|
126
|
+
<AiInput
|
|
127
|
+
send={async (input) => {
|
|
128
|
+
const res = await fetch('/api/chat', {
|
|
129
|
+
method: 'POST',
|
|
130
|
+
body: JSON.stringify({ message: input }),
|
|
131
|
+
})
|
|
132
|
+
return res.json()
|
|
133
|
+
}}
|
|
134
|
+
/>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
</details>
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## GPT + Whisper Example
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
<AiInput
|
|
146
|
+
placeholder="Ask anything..."
|
|
147
|
+
send={async (input) => {
|
|
148
|
+
// Text → GPT
|
|
149
|
+
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
150
|
+
method: 'POST',
|
|
151
|
+
headers: {
|
|
152
|
+
'Authorization': `Bearer ${token}`,
|
|
153
|
+
'Content-Type': 'application/json',
|
|
154
|
+
},
|
|
155
|
+
body: JSON.stringify({
|
|
156
|
+
model: 'gpt-4',
|
|
157
|
+
messages: [{ role: 'user', content: input as string }],
|
|
158
|
+
}),
|
|
159
|
+
})
|
|
160
|
+
return response.json()
|
|
161
|
+
}}
|
|
162
|
+
sendAudio={async (blob) => {
|
|
163
|
+
// Audio → Whisper
|
|
164
|
+
const formData = new FormData()
|
|
165
|
+
formData.append('file', blob, 'audio.webm')
|
|
166
|
+
formData.append('model', 'whisper-1')
|
|
167
|
+
|
|
168
|
+
const response = await fetch('https://api.openai.com/v1/audio/transcriptions', {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
171
|
+
body: formData,
|
|
172
|
+
})
|
|
173
|
+
return response.json()
|
|
174
|
+
}}
|
|
175
|
+
onTranscription={(text) => console.log('Transcribed:', text)}
|
|
176
|
+
/>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## API Reference
|
|
182
|
+
|
|
183
|
+
### Props
|
|
184
|
+
|
|
185
|
+
| Prop | Type | Required | Description |
|
|
186
|
+
|------|------|:--------:|-------------|
|
|
187
|
+
| `send` | `(input: string \| Blob) => Promise<any>` | ✅ | Transport function for sending input |
|
|
188
|
+
| `sendAudio` | `(blob: Blob) => Promise<any>` | | Separate transport for audio (uses `send` if not provided) |
|
|
189
|
+
| `placeholder` | `string` | | Input placeholder text |
|
|
190
|
+
| `disabled` | `boolean` | | Disable the input |
|
|
191
|
+
| `className` | `string` | | Additional CSS classes |
|
|
192
|
+
| `rateLimit` | `{ cooldownMs, maxRequests, windowMs }` | | Rate limiting configuration |
|
|
193
|
+
| `audioConfig` | `{ maxDurationMs, mimeTypes }` | | Audio recording settings |
|
|
194
|
+
| `onSuccess` | `(result: any) => void` | | Called on successful response |
|
|
195
|
+
| `onError` | `(error: Error) => void` | | Called on error |
|
|
196
|
+
| `onTranscription` | `(text: string) => void` | | Called when audio is transcribed |
|
|
197
|
+
| `children` | `(props: RenderProps) => ReactNode` | | Render prop for headless usage |
|
|
198
|
+
|
|
199
|
+
### Render Props (Headless Mode)
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
<AiInput send={sendFn}>
|
|
203
|
+
{(props) => (
|
|
204
|
+
// Full control over UI
|
|
205
|
+
)}
|
|
206
|
+
</AiInput>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| Prop | Type | Description |
|
|
210
|
+
|------|------|-------------|
|
|
211
|
+
| `text` | `string` | Current text value |
|
|
212
|
+
| `setText` | `(value: string) => void` | Update text |
|
|
213
|
+
| `submit` | `() => void` | Submit current input |
|
|
214
|
+
| `canSubmit` | `boolean` | Whether submit is allowed |
|
|
215
|
+
| `state` | `'idle' \| 'loading' \| 'success' \| 'error' \| 'recording'` | Current state |
|
|
216
|
+
| `isRecording` | `boolean` | Audio recording active |
|
|
217
|
+
| `startRecording` | `() => Promise<void>` | Start recording |
|
|
218
|
+
| `stopRecording` | `() => void` | Stop and send recording |
|
|
219
|
+
| `cancelRecording` | `() => void` | Discard recording |
|
|
220
|
+
| `audioLevels` | `number[]` | Waveform data (0-1) |
|
|
221
|
+
| `recordingDuration` | `number` | Recording time in ms |
|
|
222
|
+
| `error` | `Error \| null` | Current error |
|
|
223
|
+
| `reset` | `() => void` | Reset to idle state |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Styling
|
|
228
|
+
|
|
229
|
+
### Prepacked CSS (Recommended)
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
import 'ai-input-react/styles.css'
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Includes dark theme with zinc/amber colors, waveform visualization, and smooth animations.
|
|
236
|
+
|
|
237
|
+
### Custom Styling (Tailwind)
|
|
238
|
+
|
|
239
|
+
If using Tailwind, don't import the CSS file. The component uses Tailwind utility classes that will be processed by your build.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Security
|
|
244
|
+
|
|
245
|
+
> ⚠️ **Never store API keys in frontend code!**
|
|
246
|
+
|
|
247
|
+
Use short-lived tokens from your backend:
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
// ❌ Dangerous
|
|
251
|
+
const API_KEY = 'sk-...'
|
|
252
|
+
|
|
253
|
+
// ✅ Safe
|
|
254
|
+
const token = await getTokenFromBackend()
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Browser Support
|
|
260
|
+
|
|
261
|
+
| Browser | Version |
|
|
262
|
+
|---------|---------|
|
|
263
|
+
| Chrome | 49+ |
|
|
264
|
+
| Firefox | 36+ |
|
|
265
|
+
| Safari | 14.1+ |
|
|
266
|
+
| Edge | 79+ |
|
|
267
|
+
|
|
268
|
+
Audio recording requires HTTPS (or localhost) and microphone permission.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Contributing
|
|
273
|
+
|
|
274
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
275
|
+
|
|
276
|
+
1. Fork the repository
|
|
277
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
278
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
279
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
280
|
+
5. Open a Pull Request
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Issues & Support
|
|
285
|
+
|
|
286
|
+
- 🐛 **Bug Reports**: [Open an issue](https://github.com/Soptik1290/ai-input/issues/new)
|
|
287
|
+
- 💡 **Feature Requests**: [Open an issue](https://github.com/Soptik1290/ai-input/issues/new)
|
|
288
|
+
- 💬 **Questions**: [GitHub Discussions](https://github.com/Soptik1290/ai-input/discussions)
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## License
|
|
293
|
+
|
|
294
|
+
[MIT](LICENSE) © 2024
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Current state of the AiInput component
|
|
6
|
+
*/
|
|
7
|
+
type AiInputState = 'idle' | 'loading' | 'success' | 'error' | 'rate-limited' | 'recording';
|
|
8
|
+
/**
|
|
9
|
+
* Rate limiting configuration for UI protection
|
|
10
|
+
* Note: This is soft rate limiting for UX only.
|
|
11
|
+
* Actual rate limiting should be handled by the AI provider.
|
|
12
|
+
*/
|
|
13
|
+
interface RateLimitConfig {
|
|
14
|
+
/** Cooldown between requests in milliseconds */
|
|
15
|
+
cooldownMs: number;
|
|
16
|
+
/** Maximum number of requests allowed in the time window */
|
|
17
|
+
maxRequests: number;
|
|
18
|
+
/** Time window in milliseconds for counting requests */
|
|
19
|
+
windowMs: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Audio recording configuration
|
|
23
|
+
*/
|
|
24
|
+
interface AudioConfig {
|
|
25
|
+
/** Maximum recording duration in milliseconds */
|
|
26
|
+
maxDurationMs: number;
|
|
27
|
+
/**
|
|
28
|
+
* Allowed MIME types for recording
|
|
29
|
+
* @example ['audio/webm', 'audio/mp4', 'audio/ogg']
|
|
30
|
+
*/
|
|
31
|
+
mimeTypes: string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Transport function for sending input to AI API.
|
|
35
|
+
* Must be provided by the host application.
|
|
36
|
+
*
|
|
37
|
+
* @param input - Text string or audio Blob to send
|
|
38
|
+
* @returns Promise resolving to the API response
|
|
39
|
+
*/
|
|
40
|
+
type SendFunction = (input: string | Blob) => Promise<unknown>;
|
|
41
|
+
/**
|
|
42
|
+
* Props passed to render function for headless usage
|
|
43
|
+
*/
|
|
44
|
+
interface AiInputRenderProps {
|
|
45
|
+
/** Current component state */
|
|
46
|
+
state: AiInputState;
|
|
47
|
+
/** Error if state is 'error' */
|
|
48
|
+
error: Error | null;
|
|
49
|
+
/** Result from last successful request */
|
|
50
|
+
result: unknown;
|
|
51
|
+
/** Current text value (controlled) */
|
|
52
|
+
text: string;
|
|
53
|
+
/** Update text value */
|
|
54
|
+
setText: (value: string) => void;
|
|
55
|
+
/** Submit current text or audio */
|
|
56
|
+
submit: () => void;
|
|
57
|
+
/** Whether submit is currently allowed */
|
|
58
|
+
canSubmit: boolean;
|
|
59
|
+
/** Whether currently recording */
|
|
60
|
+
isRecording: boolean;
|
|
61
|
+
/** Start audio recording */
|
|
62
|
+
startRecording: () => Promise<void>;
|
|
63
|
+
/** Stop audio recording and send */
|
|
64
|
+
stopRecording: () => void;
|
|
65
|
+
/** Cancel audio recording (discard) */
|
|
66
|
+
cancelRecording: () => void;
|
|
67
|
+
/** Current recording duration in milliseconds */
|
|
68
|
+
recordingDuration: number;
|
|
69
|
+
/** Maximum recording duration in milliseconds */
|
|
70
|
+
maxRecordingDuration: number;
|
|
71
|
+
/** Audio levels for waveform visualization (0-1 normalized, 12 bars) */
|
|
72
|
+
audioLevels: number[];
|
|
73
|
+
/** Remaining cooldown time in milliseconds */
|
|
74
|
+
cooldownRemaining: number;
|
|
75
|
+
/** Remaining requests in current window */
|
|
76
|
+
requestsRemaining: number;
|
|
77
|
+
/** Reset component to idle state */
|
|
78
|
+
reset: () => void;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Props for the AiInput component
|
|
82
|
+
*/
|
|
83
|
+
interface AiInputProps {
|
|
84
|
+
/**
|
|
85
|
+
* Transport function for sending input to AI API.
|
|
86
|
+
* Must be provided by the host application.
|
|
87
|
+
*/
|
|
88
|
+
send: SendFunction;
|
|
89
|
+
/**
|
|
90
|
+
* Transport function specifically for audio (optional).
|
|
91
|
+
* If provided, audio will be sent via this function.
|
|
92
|
+
* If not provided, audio will be sent via `send`.
|
|
93
|
+
*/
|
|
94
|
+
sendAudio?: SendFunction;
|
|
95
|
+
/** Rate limiting configuration (optional) */
|
|
96
|
+
rateLimit?: Partial<RateLimitConfig>;
|
|
97
|
+
/** Audio configuration (optional) */
|
|
98
|
+
audioConfig?: Partial<AudioConfig>;
|
|
99
|
+
/** Callback when request succeeds */
|
|
100
|
+
onSuccess?: (result: unknown) => void;
|
|
101
|
+
/** Callback when request fails */
|
|
102
|
+
onError?: (error: Error) => void;
|
|
103
|
+
/**
|
|
104
|
+
* Callback when audio transcription is received.
|
|
105
|
+
* Use this to set the text in the input after transcription.
|
|
106
|
+
*/
|
|
107
|
+
onTranscription?: (text: string) => void;
|
|
108
|
+
/**
|
|
109
|
+
* Render function for headless usage.
|
|
110
|
+
* When provided, default UI is not rendered.
|
|
111
|
+
*/
|
|
112
|
+
children?: (props: AiInputRenderProps) => ReactNode;
|
|
113
|
+
/** Placeholder text for input */
|
|
114
|
+
placeholder?: string;
|
|
115
|
+
/** Additional CSS classes for the container */
|
|
116
|
+
className?: string;
|
|
117
|
+
/** Whether the input is disabled */
|
|
118
|
+
disabled?: boolean;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Options for useRateLimiter hook
|
|
122
|
+
*/
|
|
123
|
+
interface UseRateLimiterOptions {
|
|
124
|
+
cooldownMs: number;
|
|
125
|
+
maxRequests: number;
|
|
126
|
+
windowMs: number;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Return type for useRateLimiter hook
|
|
130
|
+
*/
|
|
131
|
+
interface UseRateLimiterReturn {
|
|
132
|
+
canRequest: boolean;
|
|
133
|
+
cooldownRemaining: number;
|
|
134
|
+
requestsRemaining: number;
|
|
135
|
+
recordRequest: () => void;
|
|
136
|
+
reset: () => void;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Options for useAudioRecorder hook
|
|
140
|
+
*/
|
|
141
|
+
interface UseAudioRecorderOptions {
|
|
142
|
+
maxDurationMs: number;
|
|
143
|
+
mimeTypes: string[];
|
|
144
|
+
onRecordingComplete?: (blob: Blob) => void;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Return type for useAudioRecorder hook
|
|
148
|
+
*/
|
|
149
|
+
interface UseAudioRecorderReturn {
|
|
150
|
+
isRecording: boolean;
|
|
151
|
+
isSupported: boolean;
|
|
152
|
+
duration: number;
|
|
153
|
+
audioBlob: Blob | null;
|
|
154
|
+
audioLevels: number[];
|
|
155
|
+
error: Error | null;
|
|
156
|
+
startRecording: () => Promise<void>;
|
|
157
|
+
stopRecording: () => void;
|
|
158
|
+
cancelRecording: () => void;
|
|
159
|
+
reset: () => void;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Options for useAiInput hook
|
|
163
|
+
*/
|
|
164
|
+
interface UseAiInputOptions {
|
|
165
|
+
send: SendFunction;
|
|
166
|
+
sendAudio?: SendFunction;
|
|
167
|
+
rateLimit?: Partial<RateLimitConfig>;
|
|
168
|
+
audioConfig?: Partial<AudioConfig>;
|
|
169
|
+
onSuccess?: (result: unknown) => void;
|
|
170
|
+
onError?: (error: Error) => void;
|
|
171
|
+
onTranscription?: (text: string) => void;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Return type for useAiInput hook
|
|
175
|
+
*/
|
|
176
|
+
type UseAiInputReturn = AiInputRenderProps;
|
|
177
|
+
/** @deprecated Use AiInputProps without mode */
|
|
178
|
+
type AiInputMode = 'text' | 'audio';
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* AiInput Component
|
|
182
|
+
*
|
|
183
|
+
* A React component for text/audio input with AI API integration.
|
|
184
|
+
* Unified design with text input and audio recording in a single component.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* // Basic usage
|
|
188
|
+
* <AiInput
|
|
189
|
+
* send={async (input) => {
|
|
190
|
+
* const response = await fetch('/api/chat', {
|
|
191
|
+
* method: 'POST',
|
|
192
|
+
* body: JSON.stringify({ message: input }),
|
|
193
|
+
* })
|
|
194
|
+
* return response.json()
|
|
195
|
+
* }}
|
|
196
|
+
* onSuccess={(result) => console.log(result)}
|
|
197
|
+
* />
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* // With separate audio handler and transcription
|
|
201
|
+
* <AiInput
|
|
202
|
+
* send={sendTextFn}
|
|
203
|
+
* sendAudio={sendAudioFn}
|
|
204
|
+
* onTranscription={(text) => console.log('Transcribed:', text)}
|
|
205
|
+
* />
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* // Headless mode with custom UI
|
|
209
|
+
* <AiInput send={sendFn}>
|
|
210
|
+
* {({ text, setText, submit, state, isRecording, audioLevels }) => (
|
|
211
|
+
* <div>
|
|
212
|
+
* {isRecording ? (
|
|
213
|
+
* <MyWaveform levels={audioLevels} />
|
|
214
|
+
* ) : (
|
|
215
|
+
* <input value={text} onChange={(e) => setText(e.target.value)} />
|
|
216
|
+
* )}
|
|
217
|
+
* <button onClick={submit}>Send</button>
|
|
218
|
+
* </div>
|
|
219
|
+
* )}
|
|
220
|
+
* </AiInput>
|
|
221
|
+
*/
|
|
222
|
+
declare function AiInput({ send, sendAudio, rateLimit, audioConfig, onSuccess, onError, onTranscription, children, placeholder, className, disabled, }: AiInputProps): react_jsx_runtime.JSX.Element;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Main hook for AI input functionality.
|
|
226
|
+
* Combines rate limiting, audio recording, and API communication.
|
|
227
|
+
* Unified design - text and audio in single component.
|
|
228
|
+
*
|
|
229
|
+
* @param options - Configuration options
|
|
230
|
+
* @returns Complete state and controls for AI input
|
|
231
|
+
*/
|
|
232
|
+
declare function useAiInput(options: UseAiInputOptions): UseAiInputReturn;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Hook for audio recording using Web APIs.
|
|
236
|
+
* Uses navigator.mediaDevices, MediaRecorder, and Web Audio API for visualization.
|
|
237
|
+
*
|
|
238
|
+
* @param options - Audio recording configuration
|
|
239
|
+
* @returns Audio recorder state and controls
|
|
240
|
+
*/
|
|
241
|
+
declare function useAudioRecorder(options?: Partial<UseAudioRecorderOptions>): UseAudioRecorderReturn;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Hook for soft rate limiting at the UI level.
|
|
245
|
+
* Provides UX protection by tracking requests and enforcing cooldowns.
|
|
246
|
+
*
|
|
247
|
+
* Note: This is not a security measure. Actual rate limiting
|
|
248
|
+
* should be handled by the AI provider or backend.
|
|
249
|
+
*
|
|
250
|
+
* @param options - Rate limiting configuration
|
|
251
|
+
* @returns Rate limiter state and controls
|
|
252
|
+
*/
|
|
253
|
+
declare function useRateLimiter(options?: Partial<UseRateLimiterOptions>): UseRateLimiterReturn;
|
|
254
|
+
|
|
255
|
+
export { AiInput, type AiInputMode, type AiInputProps, type AiInputRenderProps, type AiInputState, type AudioConfig, type RateLimitConfig, type SendFunction, type UseAiInputOptions, type UseAiInputReturn, type UseAudioRecorderOptions, type UseAudioRecorderReturn, type UseRateLimiterOptions, type UseRateLimiterReturn, useAiInput, useAudioRecorder, useRateLimiter };
|