ai-props 0.1.0 → 0.1.2
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 +168 -51
- package/dist/AI.d.ts +18 -24
- package/dist/AI.d.ts.map +1 -1
- package/dist/ai-props.es.js +1531 -3757
- package/dist/ai-props.umd.js +10 -10
- package/dist/examples/BlogList.d.ts.map +1 -1
- package/dist/examples/BlogList.fixture.d.ts.map +1 -1
- package/dist/examples/HeroSection.d.ts.map +1 -1
- package/dist/examples/HeroSection.fixture.d.ts.map +1 -1
- package/dist/utils/schema.d.ts.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# ai-props
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/ai-props)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
3
6
|
A React component package that provides an AI component for generating and spreading AI-generated props to child components.
|
|
4
7
|
|
|
5
8
|
## Installation
|
|
@@ -8,30 +11,125 @@ A React component package that provides an AI component for generating and sprea
|
|
|
8
11
|
npm install ai-props
|
|
9
12
|
```
|
|
10
13
|
|
|
11
|
-
##
|
|
14
|
+
## Usage
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
- `react` (^18.2.0)
|
|
15
|
-
- `react-dom` (^18.2.0)
|
|
16
|
-
- `@types/react` (^18.2.0)
|
|
17
|
-
- `@types/react-dom` (^18.2.0)
|
|
16
|
+
The `AI` component mirrors the `generateObject` function from the `ai` package and spreads the generated object's properties to its children.
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
- `ai` (^4.0.18)
|
|
21
|
-
- `@ai-sdk/openai` (^1.0.8)
|
|
22
|
-
- `clsx` (^2.1.1)
|
|
23
|
-
- `tailwind-merge` (^2.5.5)
|
|
24
|
-
- `zod` (^3.22.4)
|
|
18
|
+
### Model Configuration
|
|
25
19
|
|
|
26
|
-
|
|
20
|
+
The AI component supports both string-based OpenAI models and provider-specific model objects:
|
|
27
21
|
|
|
28
|
-
```
|
|
29
|
-
|
|
22
|
+
```tsx
|
|
23
|
+
// Simple string-based OpenAI model (recommended for OpenAI)
|
|
24
|
+
<AI
|
|
25
|
+
model='gpt-4'
|
|
26
|
+
schema={schema}
|
|
27
|
+
prompt='Generate content'
|
|
28
|
+
/>
|
|
29
|
+
|
|
30
|
+
// Provider-specific model object (required for other providers)
|
|
31
|
+
import { anthropic } from '@ai-sdk/anthropic'
|
|
32
|
+
|
|
33
|
+
const model = anthropic('claude-2')
|
|
34
|
+
<AI
|
|
35
|
+
model={model}
|
|
36
|
+
schema={schema}
|
|
37
|
+
prompt='Generate content'
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
### Streaming Support
|
|
41
|
+
|
|
42
|
+
The AI component supports real-time streaming of generated content, providing a more interactive user experience:
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
<AI
|
|
46
|
+
model='gpt-4'
|
|
47
|
+
stream={true}
|
|
48
|
+
schema={{
|
|
49
|
+
title: 'string',
|
|
50
|
+
content: 'string'
|
|
51
|
+
}}
|
|
52
|
+
prompt='Generate an article about React'
|
|
53
|
+
>
|
|
54
|
+
{(props, { isStreaming }) => (
|
|
55
|
+
<article className={isStreaming ? 'animate-pulse' : ''}>
|
|
56
|
+
<h1>{props.title}</h1>
|
|
57
|
+
<div>{props.content}</div>
|
|
58
|
+
{isStreaming && (
|
|
59
|
+
<div className='text-gray-500'>Generating content...</div>
|
|
60
|
+
)}
|
|
61
|
+
</article>
|
|
62
|
+
)}
|
|
63
|
+
</AI>
|
|
30
64
|
```
|
|
31
65
|
|
|
32
|
-
|
|
66
|
+
When using streaming:
|
|
67
|
+
- Set `stream={true}` to enable real-time updates
|
|
68
|
+
- Access streaming status via `isStreaming` in render prop
|
|
69
|
+
- UI updates automatically as content arrives
|
|
70
|
+
- Maintain type safety with your schema
|
|
71
|
+
- Reduced time to first content display
|
|
72
|
+
|
|
73
|
+
### API Proxy Integration
|
|
33
74
|
|
|
34
|
-
|
|
75
|
+
For enhanced security and control, you can route requests through your own API endpoint:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
<AI
|
|
79
|
+
model='gpt-4'
|
|
80
|
+
apiEndpoint='/api/generate'
|
|
81
|
+
headers={{
|
|
82
|
+
'Authorization': 'Bearer ${process.env.API_KEY}',
|
|
83
|
+
'X-Custom-Header': 'value'
|
|
84
|
+
}}
|
|
85
|
+
schema={schema}
|
|
86
|
+
prompt='Generate content'
|
|
87
|
+
/>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Your API endpoint should:
|
|
91
|
+
- Accept the same parameters as the AI provider
|
|
92
|
+
- Return compatible streaming or non-streaming responses
|
|
93
|
+
- Handle authentication and rate limiting
|
|
94
|
+
- Implement proper error handling
|
|
95
|
+
|
|
96
|
+
Benefits of using an API proxy:
|
|
97
|
+
- Keep API keys secure on your server
|
|
98
|
+
- Add custom request validation
|
|
99
|
+
- Implement usage tracking
|
|
100
|
+
- Control model access and costs
|
|
101
|
+
- Add custom error handling
|
|
102
|
+
|
|
103
|
+
Example API endpoint implementation:
|
|
104
|
+
```typescript
|
|
105
|
+
// pages/api/generate.ts
|
|
106
|
+
import { OpenAIStream } from 'ai'
|
|
107
|
+
|
|
108
|
+
export async function POST(req: Request) {
|
|
109
|
+
const { prompt, schema, stream } = await req.json()
|
|
110
|
+
|
|
111
|
+
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers: {
|
|
114
|
+
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
|
|
115
|
+
'Content-Type': 'application/json',
|
|
116
|
+
},
|
|
117
|
+
body: JSON.stringify({
|
|
118
|
+
model: 'gpt-4',
|
|
119
|
+
messages: [{ role: 'user', content: prompt }],
|
|
120
|
+
stream: stream,
|
|
121
|
+
}),
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
if (stream) {
|
|
125
|
+
const stream = OpenAIStream(response)
|
|
126
|
+
return new Response(stream)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const json = await response.json()
|
|
130
|
+
return Response.json(json)
|
|
131
|
+
}
|
|
132
|
+
```
|
|
35
133
|
|
|
36
134
|
### Simplified Schema Interface
|
|
37
135
|
|
|
@@ -52,7 +150,7 @@ function MyComponent() {
|
|
|
52
150
|
description: 'website meta description',
|
|
53
151
|
tags: ['SEO-optimized meta tags']
|
|
54
152
|
}}
|
|
55
|
-
prompt=
|
|
153
|
+
prompt='Generate product details'
|
|
56
154
|
>
|
|
57
155
|
{(props) => (
|
|
58
156
|
<article>
|
|
@@ -98,7 +196,7 @@ function MyComponent() {
|
|
|
98
196
|
return (
|
|
99
197
|
<AI
|
|
100
198
|
schema={schema}
|
|
101
|
-
prompt=
|
|
199
|
+
prompt='Generate a title and description for a blog post about React'
|
|
102
200
|
>
|
|
103
201
|
{(props) => (
|
|
104
202
|
<article>
|
|
@@ -144,17 +242,17 @@ The `AI` component accepts all props from the `generateObject` function:
|
|
|
144
242
|
|
|
145
243
|
### Array Output Mode
|
|
146
244
|
|
|
147
|
-
The `AI` component supports generating and rendering arrays of items using the `output=
|
|
245
|
+
The `AI` component supports generating and rendering arrays of items using the `output='array'` prop. When using array output mode, you can also enable CSS Grid layout with the `cols` prop:
|
|
148
246
|
|
|
149
247
|
```tsx
|
|
150
248
|
<AI
|
|
151
249
|
schema={blogSchema}
|
|
152
|
-
prompt=
|
|
153
|
-
output=
|
|
250
|
+
prompt='Generate 6 blog post previews'
|
|
251
|
+
output='array'
|
|
154
252
|
cols={3}
|
|
155
|
-
gap=
|
|
156
|
-
className=
|
|
157
|
-
itemClassName=
|
|
253
|
+
gap='2rem'
|
|
254
|
+
className='grid-container'
|
|
255
|
+
itemClassName='grid-item'
|
|
158
256
|
>
|
|
159
257
|
{(props) => (
|
|
160
258
|
<article>{/* Item content */}</article>
|
|
@@ -174,8 +272,8 @@ The `AI` component integrates with `clsx` and `tailwind-merge` for flexible styl
|
|
|
174
272
|
|
|
175
273
|
```tsx
|
|
176
274
|
<AI
|
|
177
|
-
className=
|
|
178
|
-
itemClassName=
|
|
275
|
+
className='max-w-7xl mx-auto px-4 py-16 grid-cols-1 md:grid-cols-2 lg:grid-cols-3'
|
|
276
|
+
itemClassName='bg-white p-6 rounded-lg shadow-md h-full flex flex-col'
|
|
179
277
|
>
|
|
180
278
|
{/* Component content */}
|
|
181
279
|
</AI>
|
|
@@ -211,24 +309,24 @@ export function HeroSection() {
|
|
|
211
309
|
return (
|
|
212
310
|
<AI<typeof heroSchema>
|
|
213
311
|
schema={heroSchema}
|
|
214
|
-
prompt=
|
|
215
|
-
className=
|
|
312
|
+
prompt='Generate a hero section for an AI-powered SaaS product waitlist landing page'
|
|
313
|
+
className='bg-gradient-to-br from-blue-50 to-indigo-50'
|
|
216
314
|
>
|
|
217
315
|
{(props) => (
|
|
218
|
-
<div className=
|
|
219
|
-
<h1 className=
|
|
316
|
+
<div className='max-w-6xl mx-auto px-4 py-16'>
|
|
317
|
+
<h1 className='text-5xl font-bold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-indigo-600'>
|
|
220
318
|
{props.headline}
|
|
221
319
|
</h1>
|
|
222
|
-
<p className=
|
|
223
|
-
<button className=
|
|
320
|
+
<p className='text-xl text-gray-600 mb-8'>{props.subheadline}</p>
|
|
321
|
+
<button className='bg-blue-600 text-white px-8 py-3 rounded-lg text-lg font-medium hover:bg-blue-700 transition-colors'>
|
|
224
322
|
{props.ctaText}
|
|
225
323
|
</button>
|
|
226
|
-
<div className=
|
|
227
|
-
<h2 className=
|
|
228
|
-
<ul className=
|
|
324
|
+
<div className='mt-12'>
|
|
325
|
+
<h2 className='text-2xl font-semibold mb-4'>Perfect for {props.targetAudience}</h2>
|
|
326
|
+
<ul className='grid grid-cols-1 md:grid-cols-2 gap-4'>
|
|
229
327
|
{props.benefits.map((benefit, index) => (
|
|
230
|
-
<li key={index} className=
|
|
231
|
-
<span className=
|
|
328
|
+
<li key={index} className='flex items-start bg-white p-4 rounded-lg shadow-sm'>
|
|
329
|
+
<span className='text-blue-500 mr-2'>✓</span>
|
|
232
330
|
{benefit}
|
|
233
331
|
</li>
|
|
234
332
|
))}
|
|
@@ -239,7 +337,6 @@ export function HeroSection() {
|
|
|
239
337
|
</AI>
|
|
240
338
|
)
|
|
241
339
|
}
|
|
242
|
-
```
|
|
243
340
|
|
|
244
341
|
#### Blog List Example
|
|
245
342
|
|
|
@@ -266,24 +363,24 @@ export function BlogList() {
|
|
|
266
363
|
return (
|
|
267
364
|
<AI<typeof blogSchema>
|
|
268
365
|
schema={blogSchema}
|
|
269
|
-
prompt=
|
|
270
|
-
output=
|
|
366
|
+
prompt='Generate 6 blog post previews about AI and machine learning'
|
|
367
|
+
output='array'
|
|
271
368
|
cols={3}
|
|
272
|
-
gap=
|
|
273
|
-
className=
|
|
274
|
-
itemClassName=
|
|
369
|
+
gap='2rem'
|
|
370
|
+
className='max-w-7xl mx-auto px-4 py-16 grid-cols-1 md:grid-cols-2 lg:grid-cols-3'
|
|
371
|
+
itemClassName='h-full'
|
|
275
372
|
>
|
|
276
373
|
{(props) => (
|
|
277
|
-
<article className=
|
|
278
|
-
<div className=
|
|
374
|
+
<article className='bg-white p-6 rounded-lg shadow-md h-full flex flex-col'>
|
|
375
|
+
<div className='text-sm text-gray-500 mb-2 flex items-center justify-between'>
|
|
279
376
|
<span>{props.category}</span>
|
|
280
377
|
<span>{props.readTime}</span>
|
|
281
378
|
</div>
|
|
282
|
-
<h2 className=
|
|
283
|
-
<p className=
|
|
284
|
-
<div className=
|
|
379
|
+
<h2 className='text-xl font-semibold mb-3'>{props.title}</h2>
|
|
380
|
+
<p className='text-gray-600 mb-4 flex-grow'>{props.excerpt}</p>
|
|
381
|
+
<div className='flex flex-wrap gap-2 mt-auto'>
|
|
285
382
|
{props.tags.map((tag, index) => (
|
|
286
|
-
<span key={index} className=
|
|
383
|
+
<span key={index} className='bg-gray-100 text-gray-600 px-3 py-1 rounded-full text-sm'>
|
|
287
384
|
{tag}
|
|
288
385
|
</span>
|
|
289
386
|
))}
|
|
@@ -293,7 +390,6 @@ export function BlogList() {
|
|
|
293
390
|
</AI>
|
|
294
391
|
)
|
|
295
392
|
}
|
|
296
|
-
```
|
|
297
393
|
|
|
298
394
|
## Development
|
|
299
395
|
|
|
@@ -302,6 +398,27 @@ This package uses:
|
|
|
302
398
|
- Vitest for testing
|
|
303
399
|
- React Cosmos for component development and testing
|
|
304
400
|
|
|
401
|
+
## Dependencies
|
|
402
|
+
|
|
403
|
+
This package requires the following peer dependencies:
|
|
404
|
+
- `react` (^18.2.0)
|
|
405
|
+
- `react-dom` (^18.2.0)
|
|
406
|
+
- `@types/react` (^18.2.0)
|
|
407
|
+
- `@types/react-dom` (^18.2.0)
|
|
408
|
+
|
|
409
|
+
And the following runtime dependencies:
|
|
410
|
+
- `ai` (^4.0.18)
|
|
411
|
+
- `@ai-sdk/openai` (^1.0.8)
|
|
412
|
+
- `clsx` (^2.1.1)
|
|
413
|
+
- `tailwind-merge` (^2.5.5)
|
|
414
|
+
- `zod` (^3.22.4)
|
|
415
|
+
|
|
416
|
+
Make sure to install these dependencies if they're not already in your project:
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
npm install ai @ai-sdk/openai clsx tailwind-merge zod
|
|
420
|
+
```
|
|
421
|
+
|
|
305
422
|
## License
|
|
306
423
|
|
|
307
424
|
MIT
|
package/dist/AI.d.ts
CHANGED
|
@@ -1,33 +1,27 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
1
|
import { z } from 'zod';
|
|
3
|
-
import type
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
type TelemetrySettings = {
|
|
8
|
-
isEnabled?: boolean;
|
|
9
|
-
recordInputs?: boolean;
|
|
10
|
-
recordOutputs?: boolean;
|
|
11
|
-
functionId?: string;
|
|
12
|
-
metadata?: Record<string, AttributeValue>;
|
|
2
|
+
import { type SchemaObject } from './utils/schema';
|
|
3
|
+
type ModelType = string | {
|
|
4
|
+
provider: string;
|
|
5
|
+
model: string;
|
|
13
6
|
};
|
|
14
|
-
|
|
15
|
-
children: (props: T) => ReactNode;
|
|
16
|
-
prompt: string;
|
|
7
|
+
interface AIProps<T extends Record<string, unknown>, O extends 'object' | 'array' = 'object'> {
|
|
17
8
|
schema: z.ZodSchema<T> | SchemaObject;
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
prompt: string;
|
|
10
|
+
model?: ModelType;
|
|
11
|
+
output?: O;
|
|
20
12
|
count?: number;
|
|
21
13
|
cols?: number;
|
|
22
|
-
|
|
14
|
+
mode?: 'json';
|
|
15
|
+
stream?: boolean;
|
|
16
|
+
apiEndpoint?: string;
|
|
17
|
+
headers?: Record<string, string>;
|
|
18
|
+
experimental_telemetry?: boolean;
|
|
19
|
+
experimental_providerMetadata?: boolean;
|
|
23
20
|
className?: string;
|
|
24
21
|
itemClassName?: string;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
experimental_providerMetadata?: LanguageModelV1ProviderMetadata;
|
|
30
|
-
};
|
|
31
|
-
export declare function AI<T>({ children, prompt, schema: rawSchema, model, output, count, cols, gap, className, itemClassName, schemaName, schemaDescription, mode, experimental_telemetry, experimental_providerMetadata, }: AIProps<T>): string | number | boolean | Iterable<ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
|
22
|
+
gap?: string;
|
|
23
|
+
children: (props: O extends 'array' ? T[] : T) => React.ReactNode;
|
|
24
|
+
}
|
|
25
|
+
export declare function AI<T extends Record<string, unknown>, O extends 'object' | 'array' = 'object'>({ children, prompt, schema: rawSchema, model, output, count, cols, mode, stream, apiEndpoint, headers, experimental_telemetry, experimental_providerMetadata, className, itemClassName, gap, }: AIProps<T, O>): string | number | boolean | Iterable<import("react").ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
|
32
26
|
export {};
|
|
33
27
|
//# sourceMappingURL=AI.d.ts.map
|
package/dist/AI.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AI.d.ts","sourceRoot":"","sources":["../src/AI.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AI.d.ts","sourceRoot":"","sources":["../src/AI.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,EAAuC,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAEvF,KAAK,SAAS,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE7D,UAAU,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,OAAO,GAAG,QAAQ;IAC1F,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,YAAY,CAAA;IACrC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,MAAM,CAAC,EAAE,CAAC,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,6BAA6B,CAAC,EAAE,OAAO,CAAA;IACvC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,SAAS,OAAO,GAAG,CAAC,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;CAClE;AAMD,wBAAgB,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,OAAO,GAAG,QAAQ,EAAE,EAC7F,QAAQ,EACR,MAAM,EACN,MAAM,EAAE,SAAS,EACjB,KAAe,EACf,MAAsB,EACtB,KAAK,EACL,IAAI,EACJ,IAAa,EACb,MAAc,EACd,WAAW,EACX,OAAO,EACP,sBAAsB,EACtB,6BAA6B,EAC7B,SAAS,EACT,aAAa,EACb,GAAY,GACb,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,gIAoGf"}
|