@ai-stack/payloadcms 3.2.21-beta → 3.2.23-beta
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 +186 -160
- package/dist/ai/models/anthropic/index.js.map +1 -1
- package/dist/ai/models/elevenLabs/index.js.map +1 -1
- package/dist/ai/models/google/generateImage.d.ts +9 -0
- package/dist/ai/models/google/generateImage.js +27 -0
- package/dist/ai/models/google/generateImage.js.map +1 -0
- package/dist/ai/models/google/index.d.ts +2 -0
- package/dist/ai/models/google/index.js +201 -0
- package/dist/ai/models/google/index.js.map +1 -0
- package/dist/ai/models/index.js +2 -0
- package/dist/ai/models/index.js.map +1 -1
- package/dist/ai/models/openai/index.js.map +1 -1
- package/dist/ai/schemas/lexicalJsonSchema.js.map +1 -1
- package/dist/ai/utils/editImagesWithOpenAI.js.map +1 -1
- package/dist/ai/utils/filterEditorSchemaByNodes.js +2 -1
- package/dist/ai/utils/filterEditorSchemaByNodes.js.map +1 -1
- package/dist/ai/utils/generateFileNameByPrompt.js.map +1 -1
- package/dist/defaults.js.map +1 -1
- package/dist/endpoints/index.js.map +1 -1
- package/dist/fields/ComposeField/ComposeField.js.map +1 -1
- package/dist/init.js.map +1 -1
- package/dist/libraries/handlebars/helpers.js.map +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
- package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
- package/dist/ui/Compose/Compose.js.map +1 -1
- package/dist/ui/Compose/UndoRedoActions.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js +1 -2
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +1 -1
- package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js +98 -21
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -1
- package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
- package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
- package/dist/utilities/fieldToJsonSchema.js.map +1 -1
- package/dist/utilities/updateFieldsConfig.js.map +1 -1
- package/package.json +74 -38
package/README.md
CHANGED
|
@@ -4,77 +4,90 @@
|
|
|
4
4
|
<img alt="Payload AI Plugin" src="assets/payload-ai-intro.gif" width="100%" />
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Transform content creation with intelligent automation — your models, your way</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<img alt="Supported AI Providers" src="assets/providers.png" width="100%" />
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 🚀 What is this?
|
|
8
18
|
|
|
9
|
-
The Payload AI Plugin is
|
|
19
|
+
The Payload AI Plugin is your secret weapon for turbocharged content creation. It seamlessly integrates cutting-edge AI capabilities directly into [Payload CMS](https://payloadcms.com), turning your content workflow from tedious to tremendous.
|
|
10
20
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
### 🎥 See It in Action
|
|
22
|
+
|
|
23
|
+
- **[Quick Demo](https://youtu.be/qaYukeGpuu4)** - Watch the magic happen
|
|
24
|
+
- **[Extended Demo](https://youtu.be/LEsuHbKalNY)** - Deep dive into all features
|
|
25
|
+
- **[Customization Guide](guide.md)** - Make it your own
|
|
14
26
|
|
|
15
27
|
---
|
|
16
28
|
|
|
17
|
-
|
|
29
|
+
## ⚠️ Beta Notice
|
|
18
30
|
|
|
19
|
-
|
|
31
|
+
This plugin is actively evolving. We're constantly shipping improvements and new features. Tested with Payload v3.38.0.
|
|
20
32
|
|
|
21
|
-
|
|
33
|
+
**Quick Start Tip:** Try it out with [Payload's website template](https://github.com/payloadcms/payload/tree/main/templates/website) for the smoothest experience.
|
|
22
34
|
|
|
23
|
-
|
|
35
|
+
---
|
|
24
36
|
|
|
25
|
-
## ✨
|
|
37
|
+
## ✨ Features
|
|
26
38
|
|
|
27
|
-
### Text
|
|
39
|
+
### 📝 Text & RichText Fields
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
**Content Generation Magic:**
|
|
42
|
+
- ✅ **Compose** - Generate content from scratch
|
|
43
|
+
- ✅ **Proofread** - Polish your prose (Beta)
|
|
44
|
+
- ✅ **Translate** - Break language barriers
|
|
45
|
+
- ✅ **Rephrase** - Find better ways to say it (Beta)
|
|
46
|
+
- 🔜 **Expand** - Elaborate on ideas
|
|
47
|
+
- 🔜 **Summarize** - Distill the essence
|
|
48
|
+
- 🔜 **Simplify** - Make complex things clear
|
|
37
49
|
|
|
38
|
-
### Upload
|
|
50
|
+
### 🎨 Upload Fields
|
|
39
51
|
|
|
40
|
-
- 🎙️ **Voice Generation**
|
|
41
|
-
- 🖼️ **Image Generation**
|
|
42
|
-
- Now also supports **[GPT-Image-1](https://github.com/ashbuilds/payload-ai/pull/82)** Model
|
|
52
|
+
- 🎙️ **Voice Generation** - Powered by ElevenLabs & OpenAI
|
|
53
|
+
- 🖼️ **Image Generation** - Powered by OpenAI (DALL-E & GPT-Image-1)
|
|
43
54
|
|
|
44
|
-
###
|
|
55
|
+
### 🔧 Power User Features
|
|
45
56
|
|
|
46
|
-
- 🔌 **Bring Your Own Model**
|
|
47
|
-
- 🎛️ **Field-
|
|
48
|
-
- 🔐 **Access Control
|
|
49
|
-
- 🧠 **Prompt Editor**
|
|
50
|
-
- 🌍 **
|
|
51
|
-
-
|
|
52
|
-
- ✅ **Fact Checking** (Coming Soon)
|
|
53
|
-
- 🔄 **Automated Content Workflows** (Coming Soon)
|
|
54
|
-
- 🌍 **Editor AI suggestions** (Coming Soon)
|
|
55
|
-
- 💬 **AI Chat Support** (Coming Soon)
|
|
57
|
+
- 🔌 **Bring Your Own Model** - Not limited to our defaults
|
|
58
|
+
- 🎛️ **Field-Level Prompts** - Customize AI behavior per field
|
|
59
|
+
- 🔐 **Access Control** - Lock down who can use AI features
|
|
60
|
+
- 🧠 **Prompt Editor** - Fine-tune AI instructions
|
|
61
|
+
- 🌍 **i18n Support** - Works with your multilingual setup
|
|
62
|
+
- 🎨 **Custom Components** - Extend with your own UI
|
|
56
63
|
|
|
57
|
-
|
|
64
|
+
### 🔜 Coming Soon
|
|
58
65
|
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
66
|
+
- 📊 Document Analyzer
|
|
67
|
+
- ✅ Fact Checking
|
|
68
|
+
- 🔄 Automated Workflows
|
|
69
|
+
- 💡 Editor Suggestions
|
|
70
|
+
- 💬 AI Chat Assistant
|
|
64
71
|
|
|
65
|
-
|
|
72
|
+
---
|
|
66
73
|
|
|
67
|
-
|
|
74
|
+
## 📦 Installation
|
|
68
75
|
|
|
69
76
|
```bash
|
|
70
77
|
pnpm add @ai-stack/payloadcms
|
|
71
78
|
```
|
|
72
79
|
|
|
73
|
-
|
|
80
|
+
That's it! Now let's configure it.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 🛠️ Quick Setup
|
|
74
85
|
|
|
75
|
-
|
|
86
|
+
### Step 1: Configure the Plugin
|
|
76
87
|
|
|
77
|
-
|
|
88
|
+
Add to `src/payload.config.ts`:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
78
91
|
import { payloadAiPlugin } from '@ai-stack/payloadcms'
|
|
79
92
|
|
|
80
93
|
export default buildConfig({
|
|
@@ -86,16 +99,17 @@ export default buildConfig({
|
|
|
86
99
|
debugging: false,
|
|
87
100
|
}),
|
|
88
101
|
],
|
|
89
|
-
// ...
|
|
102
|
+
// ... rest of your config
|
|
90
103
|
})
|
|
91
104
|
```
|
|
92
105
|
|
|
93
|
-
|
|
106
|
+
### Step 2: Enable AI in Your Fields
|
|
94
107
|
|
|
95
|
-
|
|
108
|
+
Add to your RichText fields (e.g., `src/collections/Posts/index.ts`):
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
96
111
|
import { PayloadAiPluginLexicalEditorFeature } from '@ai-stack/payloadcms'
|
|
97
112
|
|
|
98
|
-
// Add below in the Lexical Editor field config of you Collection or Plugin (e.g. src/collections/Posts/index.ts)
|
|
99
113
|
fields: [
|
|
100
114
|
{
|
|
101
115
|
name: 'content',
|
|
@@ -103,10 +117,8 @@ fields: [
|
|
|
103
117
|
editor: lexicalEditor({
|
|
104
118
|
features: ({ rootFeatures }) => {
|
|
105
119
|
return [
|
|
106
|
-
// ... your existing features
|
|
107
120
|
HeadingFeature({ enabledHeadingSizes: ['h1', 'h2', 'h3', 'h4'] }),
|
|
108
|
-
|
|
109
|
-
// Please add below
|
|
121
|
+
// Add this line:
|
|
110
122
|
PayloadAiPluginLexicalEditorFeature(),
|
|
111
123
|
]
|
|
112
124
|
},
|
|
@@ -115,34 +127,44 @@ fields: [
|
|
|
115
127
|
]
|
|
116
128
|
```
|
|
117
129
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
To get started, set your API keys in a `.env` file in your project root:
|
|
130
|
+
### Step 3: Add Your API Keys
|
|
121
131
|
|
|
132
|
+
Create a `.env` file in your project root. Add the keys for the providers you want to use:
|
|
122
133
|
```env
|
|
123
|
-
#
|
|
124
|
-
OPENAI_API_KEY=your-openai-api-key
|
|
134
|
+
# Text Generation - Choose your provider(s)
|
|
135
|
+
OPENAI_API_KEY=your-openai-api-key # OpenAI models (GPT-4, etc.)
|
|
136
|
+
ANTHROPIC_API_KEY=your-anthropic-api-key # Claude models
|
|
137
|
+
GOOGLE_GENERATIVE_AI_API_KEY=your-google-key # Gemini models
|
|
138
|
+
|
|
139
|
+
# Image Generation - Choose your provider(s)
|
|
140
|
+
OPENAI_API_KEY=your-openai-api-key # DALL-E (uses same key as above)
|
|
141
|
+
# OPENAI_ORG_ID=your-org-id # Required only for GPT-Image-1 model
|
|
142
|
+
GOOGLE_GENERATIVE_AI_API_KEY=your-google-key # Imagen (uses same key as above)
|
|
143
|
+
|
|
144
|
+
# Audio/Voice Generation - Choose your provider(s)
|
|
145
|
+
ELEVENLABS_API_KEY=your-elevenlabs-api-key # ElevenLabs voices
|
|
146
|
+
OPENAI_API_KEY=your-openai-api-key # OpenAI TTS (uses same key as above)
|
|
147
|
+
|
|
148
|
+
# Optional: Use custom OpenAI-compatible endpoint
|
|
149
|
+
# OPENAI_BASE_URL=https://api.openai.com/v1
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**You only need the keys for the providers you plan to use.** Mix and match based on your preferences!
|
|
125
153
|
|
|
126
|
-
# Required if using gpt-image-1 model
|
|
127
|
-
OPENAI_ORG_ID=your-org-id
|
|
128
154
|
|
|
129
|
-
|
|
130
|
-
ANTHROPIC_API_KEY=your-anthropic-api-key
|
|
131
|
-
ELEVENLABS_API_KEY=your-elevenlabs-api-key
|
|
155
|
+
**Important:** Restart your server after updating `.env` or plugin settings!
|
|
132
156
|
|
|
133
|
-
|
|
134
|
-
|
|
157
|
+
You may also need to regenerate the import map:
|
|
158
|
+
```bash
|
|
159
|
+
payload generate:importmap
|
|
135
160
|
```
|
|
136
161
|
|
|
137
|
-
> **⚠️ Important:** Restart your server after updating .env or plugin settings to apply the changes.
|
|
138
|
-
Also, you might want to run payload `generate:importmap` to regenerate the import map before starting the server.
|
|
139
162
|
---
|
|
140
163
|
|
|
141
|
-
|
|
164
|
+
## ⚙️ Advanced Configuration
|
|
165
|
+
|
|
142
166
|
<details>
|
|
143
|
-
<summary>
|
|
144
|
-
🔧 Access Control, Multi-Tenant, Media Upload
|
|
145
|
-
</summary>
|
|
167
|
+
<summary><strong>🔐 Access Control & Multi-Tenant Setup</strong></summary>
|
|
146
168
|
|
|
147
169
|
```typescript
|
|
148
170
|
import { payloadAiPlugin } from '@ai-stack/payloadcms'
|
|
@@ -153,70 +175,59 @@ export default buildConfig({
|
|
|
153
175
|
collections: {
|
|
154
176
|
[Posts.slug]: true,
|
|
155
177
|
},
|
|
156
|
-
|
|
157
|
-
//
|
|
178
|
+
|
|
179
|
+
// Enable AI for globals too
|
|
158
180
|
globals: {
|
|
159
181
|
[Home.slug]: true,
|
|
160
182
|
},
|
|
161
183
|
|
|
162
|
-
//
|
|
184
|
+
// Development helpers
|
|
163
185
|
debugging: false,
|
|
164
|
-
|
|
165
|
-
// Optional: Disable sponsor message in the console
|
|
166
186
|
disableSponsorMessage: false,
|
|
167
|
-
|
|
168
|
-
// Optional: Pre-generate prompts on server start (recommended for dev only)
|
|
169
187
|
generatePromptOnInit: process.env.NODE_ENV !== 'production',
|
|
170
188
|
|
|
171
|
-
//
|
|
189
|
+
// Specify media collection for GPT-Image-1
|
|
172
190
|
uploadCollectionSlug: "media",
|
|
173
191
|
|
|
174
|
-
//
|
|
192
|
+
// Lock down AI features
|
|
175
193
|
access: {
|
|
176
|
-
// Control who can generate AI content
|
|
177
194
|
generate: ({ req }) => req.user?.role === 'admin',
|
|
178
|
-
|
|
179
|
-
// Control who can modify AI settings and prompts
|
|
180
195
|
settings: ({ req }) => req.user?.role === 'admin',
|
|
181
196
|
},
|
|
182
197
|
|
|
198
|
+
// Customize language options
|
|
183
199
|
options: {
|
|
184
|
-
// Visit locale-codes for tags,
|
|
185
|
-
// defaults to display all language options for Translate feature
|
|
186
|
-
// https://www.npmjs.com/package/locale-codes
|
|
187
200
|
enabledLanguages: ["en-US", "zh-SG", "zh-CN", "en"],
|
|
188
201
|
},
|
|
189
202
|
|
|
190
|
-
//
|
|
203
|
+
// Reference additional fields in prompts
|
|
191
204
|
promptFields: [
|
|
192
|
-
// Expose "url" field on images collection
|
|
193
205
|
{
|
|
194
206
|
name: 'url',
|
|
195
207
|
collections: ['images'],
|
|
196
208
|
},
|
|
197
|
-
// Expose custom async function that generates markdown summary of any document
|
|
198
209
|
{
|
|
199
210
|
name: 'markdown',
|
|
200
|
-
async getter(doc, {collection})
|
|
211
|
+
async getter(doc, {collection}) {
|
|
212
|
+
return docToMarkdown(collection, doc)
|
|
213
|
+
}
|
|
201
214
|
}
|
|
202
215
|
],
|
|
203
216
|
|
|
204
|
-
//
|
|
217
|
+
// Control initial prompt generation
|
|
205
218
|
seedPrompts: ({path}) => {
|
|
206
219
|
if (path.endsWith('.meta.description')) {
|
|
207
220
|
return {
|
|
208
221
|
data: {
|
|
209
|
-
prompt: 'Generate SEO-friendly
|
|
210
|
-
// other instruction options
|
|
222
|
+
prompt: 'Generate SEO-friendly meta description: {{markdown}}',
|
|
211
223
|
}
|
|
212
224
|
}
|
|
213
225
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
// returning undefined fallbacks to default seed prompt
|
|
226
|
+
if (path.endsWith('.slug')) return false // Disable for slugs
|
|
227
|
+
return undefined // Use defaults
|
|
217
228
|
},
|
|
218
229
|
|
|
219
|
-
//
|
|
230
|
+
// Custom media upload (useful for multi-tenant)
|
|
220
231
|
mediaUpload: async (result, { request, collection }) => {
|
|
221
232
|
return request.payload.create({
|
|
222
233
|
collection,
|
|
@@ -231,112 +242,127 @@ export default buildConfig({
|
|
|
231
242
|
|
|
232
243
|
</details>
|
|
233
244
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
### OpenAI Endpoint
|
|
245
|
+
<details>
|
|
246
|
+
<summary><strong>🎨 Custom Components & Fields</strong></summary>
|
|
237
247
|
|
|
238
|
-
|
|
248
|
+
Custom fields don't automatically inherit AI capabilities. If your AI-enabled fields don't show Compose settings, manually add this component path:
|
|
239
249
|
|
|
240
250
|
```
|
|
241
|
-
|
|
251
|
+
@ai-stack/payloadcms/fields#ComposeField
|
|
242
252
|
```
|
|
243
253
|
|
|
244
|
-
|
|
254
|
+
**Debug Tip:** Enable `debugging: true` in your plugin config to see which fields have AI enabled.
|
|
255
|
+
|
|
256
|
+
</details>
|
|
245
257
|
|
|
246
|
-
|
|
258
|
+
---
|
|
247
259
|
|
|
248
|
-
|
|
260
|
+
## 📚 Documentation
|
|
249
261
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
> To view AI enabled fields, enable the `debugging` flag in your plugin config or check your server startup logs.
|
|
262
|
+
Need more details? Check out the **[Complete Setup Guide](guide.md)** for:
|
|
263
|
+
- Custom model configuration
|
|
264
|
+
- Advanced prompt engineering
|
|
265
|
+
- Field-specific customization
|
|
266
|
+
- Troubleshooting tips
|
|
256
267
|
|
|
257
268
|
---
|
|
258
269
|
|
|
259
|
-
## 🤝 Support
|
|
260
|
-
I build and maintain this in my free time because I love seeing the community benefit from it.
|
|
261
|
-
Keeping it alive takes real hours and real money (those AI credits aren’t free 😄).
|
|
270
|
+
## 🤝 Support This Project
|
|
262
271
|
|
|
263
|
-
|
|
272
|
+
Built with ❤️ in my free time. If this plugin saves you hours of work, consider fueling future development!
|
|
264
273
|
|
|
265
|
-
<a href="https://www.buymeacoffee.com/ashbuilds" target="_blank"
|
|
274
|
+
<a href="https://www.buymeacoffee.com/ashbuilds" target="_blank">
|
|
275
|
+
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="60" width="217" />
|
|
276
|
+
</a>
|
|
266
277
|
|
|
267
|
-
|
|
278
|
+
Every coffee keeps the AI models running and new features shipping. Thank you! 🙏
|
|
268
279
|
|
|
269
280
|
---
|
|
270
281
|
|
|
271
282
|
## 👥 Contributing
|
|
272
283
|
|
|
273
|
-
|
|
284
|
+
We love contributors! Whether you're fixing typos, suggesting features, or building new capabilities, all contributions are welcome.
|
|
285
|
+
|
|
286
|
+
### Ways to Contribute
|
|
287
|
+
|
|
288
|
+
- 🐛 Report bugs
|
|
289
|
+
- 💡 Suggest features
|
|
290
|
+
- 📖 Improve documentation
|
|
291
|
+
- 🔧 Submit pull requests
|
|
292
|
+
|
|
293
|
+
Join the conversation on [Payload's Discord](https://discord.com/channels/967097582721572934/1264949995656843345) and let's build something amazing together!
|
|
274
294
|
|
|
275
|
-
|
|
295
|
+
### Local Development
|
|
276
296
|
|
|
277
|
-
|
|
297
|
+
Want to hack on the plugin? Here's how:
|
|
278
298
|
|
|
279
|
-
|
|
299
|
+
#### Prerequisites
|
|
280
300
|
|
|
281
|
-
|
|
301
|
+
- Node.js (version in `.nvmrc`)
|
|
302
|
+
- pnpm
|
|
303
|
+
- Database connection (Postgres or MongoDB)
|
|
304
|
+
- Optional: AI provider API keys
|
|
282
305
|
|
|
283
|
-
|
|
284
|
-
- Node.js (see `.nvmrc`) and pnpm
|
|
285
|
-
- A database connection string for `DATABASE_URI` (Postgres or Mongo)
|
|
286
|
-
- Optional: AI provider keys to test features (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `ELEVENLABS_API_KEY`)
|
|
306
|
+
#### Setup
|
|
287
307
|
|
|
288
|
-
1) Install dependencies
|
|
289
308
|
```bash
|
|
309
|
+
# 1. Install dependencies
|
|
290
310
|
pnpm install
|
|
291
|
-
```
|
|
292
311
|
|
|
293
|
-
2
|
|
294
|
-
```bash
|
|
312
|
+
# 2. Set up environment
|
|
295
313
|
cp dev/.env.example dev/.env
|
|
296
|
-
# Edit dev/.env
|
|
297
|
-
# - Set DATABASE_URI to your DB connection string
|
|
298
|
-
# - Set PAYLOAD_SECRET to a strong random string
|
|
299
|
-
# - Optionally set AI provider keys to exercise features
|
|
300
|
-
```
|
|
314
|
+
# Edit dev/.env with your DATABASE_URI, PAYLOAD_SECRET, and API keys
|
|
301
315
|
|
|
302
|
-
3
|
|
303
|
-
```bash
|
|
316
|
+
# 3. Start development server
|
|
304
317
|
pnpm dev
|
|
305
|
-
|
|
318
|
+
# Admin UI available at http://localhost:3000
|
|
306
319
|
|
|
307
|
-
|
|
308
|
-
```bash
|
|
320
|
+
# 4. Generate types/importmap if needed
|
|
309
321
|
pnpm generate:importmap
|
|
310
|
-
```
|
|
311
|
-
Optionally regenerate Payload types:
|
|
312
|
-
```bash
|
|
313
322
|
pnpm generate:types
|
|
314
323
|
```
|
|
315
324
|
|
|
316
|
-
|
|
317
|
-
- Plugin source lives in `src/`; the dev app imports it locally.
|
|
318
|
-
- Edit files in `src/**` and refresh the dev app to validate changes.
|
|
325
|
+
#### Development Workflow
|
|
319
326
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
```
|
|
327
|
+
- Plugin source: `src/`
|
|
328
|
+
- Test app: `dev/`
|
|
329
|
+
- Edit files in `src/` and refresh to see changes
|
|
330
|
+
|
|
331
|
+
#### Testing & Quality
|
|
326
332
|
|
|
327
|
-
6) Build the plugin
|
|
328
333
|
```bash
|
|
329
|
-
pnpm
|
|
334
|
+
pnpm test # Run all tests
|
|
335
|
+
pnpm lint # ESLint
|
|
336
|
+
pnpm prettier --write . # Format code
|
|
337
|
+
pnpm build # Build plugin
|
|
330
338
|
```
|
|
331
339
|
|
|
332
|
-
|
|
340
|
+
#### Test in Another Project
|
|
341
|
+
|
|
333
342
|
```bash
|
|
334
|
-
pnpm pack
|
|
335
|
-
#
|
|
343
|
+
pnpm pack
|
|
344
|
+
# In your other project:
|
|
336
345
|
pnpm add /path/to/ai-plugin-*.tgz
|
|
337
346
|
```
|
|
338
347
|
|
|
339
|
-
Project
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
348
|
+
#### Project Structure
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
├── src/ # Plugin source code
|
|
352
|
+
├── dev/ # Test Payload app
|
|
353
|
+
│ ├── int.spec.ts # Integration tests
|
|
354
|
+
│ └── e2e.spec.ts # E2E tests
|
|
355
|
+
└── README.md # You are here!
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
<p align="center">
|
|
361
|
+
Made with ❤️ and ☕ by the community
|
|
362
|
+
</p>
|
|
363
|
+
|
|
364
|
+
<p align="center">
|
|
365
|
+
<a href="https://github.com/ashbuilds/payload-ai">Star on GitHub</a> •
|
|
366
|
+
<a href="https://discord.com/channels/967097582721572934/1264949995656843345">Join Discord</a> •
|
|
367
|
+
<a href="guide.md">Read the Guide</a>
|
|
368
|
+
</p>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ai/models/anthropic/index.ts"],"sourcesContent":["import { anthropic } from '@ai-sdk/anthropic'\n\nimport type { GenerationConfig } from '../../../types.js'\n\nimport { defaultSystemPrompt } from '../../prompts.js'\nimport { generateObject } from '../generateObject.js'\n\nconst MODEL_KEY = 'ANTH-C'\nconst MODELS = [\n 'claude-opus-4-1',\n 'claude-opus-4-0',\n 'claude-sonnet-4-0',\n 'claude-3-opus-latest',\n 'claude-3-5-haiku-latest',\n 'claude-3-5-sonnet-latest',\n 'claude-3-7-sonnet-latest',\n]\n\nexport const AnthropicConfig: GenerationConfig = {\n models: [\n {\n id: `${MODEL_KEY}-text`,\n name: 'Anthropic Claude',\n fields: ['text', 'textarea'],\n handler: (\n prompt: string,\n options: {\n extractAttachments?: boolean\n locale?: string\n maxTokens?: number\n model: string\n schema?: Record<string, any>\n system?: string\n temperature?: number\n },\n ) => {\n return generateObject(\n prompt,\n {\n ...options,\n system: options.system || defaultSystemPrompt,\n },\n anthropic(options.model),\n )\n },\n output: 'text',\n settings: {\n name: `${MODEL_KEY}-text-settings`,\n type: 'group',\n admin: {\n condition(data) {\n return data['model-id'] === `${MODEL_KEY}-text`\n },\n },\n fields: [\n {\n name: 'model',\n type: 'select',\n defaultValue: 'claude-3-5-sonnet-latest',\n label: 'Model',\n options: MODELS,\n },\n {\n type: 'row',\n fields: [\n {\n name: 'maxTokens',\n type: 'number',\n defaultValue: 5000,\n },\n {\n name: 'temperature',\n type: 'number',\n defaultValue: 0.7,\n max: 1,\n min: 0,\n },\n ],\n },\n {\n name: 'extractAttachments',\n type: 'checkbox',\n },\n ],\n label: 'Anthropic Claude Settings',\n },\n },\n {\n id: `${MODEL_KEY}-object`,\n name: 'Anthropic Claude',\n fields: ['richText'],\n handler: (text: string, options) => {\n return generateObject(\n text,\n {\n ...options,\n system: options.system || defaultSystemPrompt,\n },\n anthropic(options.model),\n )\n },\n output: 'text',\n settings: {\n name: `${MODEL_KEY}-object-settings`,\n type: 'group',\n admin: {\n condition(data) {\n return data['model-id'] === `${MODEL_KEY}-object`\n },\n },\n fields: [\n {\n name: 'model',\n type: 'select',\n defaultValue: 'claude-3-5-sonnet-latest',\n label: 'Model',\n options: MODELS,\n },\n {\n type: 'row',\n fields: [\n {\n name: 'maxTokens',\n type: 'number',\n defaultValue: 5000,\n },\n {\n name: 'temperature',\n type: 'number',\n defaultValue: 0.7,\n max: 1,\n min: 0,\n },\n ],\n },\n {\n name: 'extractAttachments',\n type: 'checkbox',\n },\n ],\n label: 'Anthropic Claude Settings',\n },\n },\n ],\n provider: 'Anthropic',\n}\n"],"names":["anthropic","defaultSystemPrompt","generateObject","MODEL_KEY","MODELS","AnthropicConfig","models","id","name","fields","handler","prompt","options","system","model","output","settings","type","admin","condition","data","defaultValue","label","max","min","text","provider"],"mappings":"AAAA,SAASA,SAAS,QAAQ,oBAAmB;AAI7C,SAASC,mBAAmB,QAAQ,mBAAkB;AACtD,SAASC,cAAc,QAAQ,uBAAsB;AAErD,MAAMC,YAAY;AAClB,MAAMC,SAAS;IACb;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,OAAO,MAAMC,kBAAoC;IAC/CC,QAAQ;QACN;YACEC,IAAI,
|
|
1
|
+
{"version":3,"sources":["../../../../src/ai/models/anthropic/index.ts"],"sourcesContent":["import { anthropic } from '@ai-sdk/anthropic'\n\nimport type { GenerationConfig } from '../../../types.js'\n\nimport { defaultSystemPrompt } from '../../prompts.js'\nimport { generateObject } from '../generateObject.js'\n\nconst MODEL_KEY = 'ANTH-C'\nconst MODELS = [\n 'claude-opus-4-1',\n 'claude-opus-4-0',\n 'claude-sonnet-4-0',\n 'claude-3-opus-latest',\n 'claude-3-5-haiku-latest',\n 'claude-3-5-sonnet-latest',\n 'claude-3-7-sonnet-latest',\n]\n\nexport const AnthropicConfig: GenerationConfig = {\n models: [\n {\n id: `${MODEL_KEY}-text`,\n name: 'Anthropic Claude',\n fields: ['text', 'textarea'],\n handler: (\n prompt: string,\n options: {\n extractAttachments?: boolean\n locale?: string\n maxTokens?: number\n model: string\n schema?: Record<string, any>\n system?: string\n temperature?: number\n },\n ) => {\n return generateObject(\n prompt,\n {\n ...options,\n system: options.system || defaultSystemPrompt,\n },\n anthropic(options.model),\n )\n },\n output: 'text',\n settings: {\n name: `${MODEL_KEY}-text-settings`,\n type: 'group',\n admin: {\n condition(data) {\n return data['model-id'] === `${MODEL_KEY}-text`\n },\n },\n fields: [\n {\n name: 'model',\n type: 'select',\n defaultValue: 'claude-3-5-sonnet-latest',\n label: 'Model',\n options: MODELS,\n },\n {\n type: 'row',\n fields: [\n {\n name: 'maxTokens',\n type: 'number',\n defaultValue: 5000,\n },\n {\n name: 'temperature',\n type: 'number',\n defaultValue: 0.7,\n max: 1,\n min: 0,\n },\n ],\n },\n {\n name: 'extractAttachments',\n type: 'checkbox',\n },\n ],\n label: 'Anthropic Claude Settings',\n },\n },\n {\n id: `${MODEL_KEY}-object`,\n name: 'Anthropic Claude',\n fields: ['richText'],\n handler: (text: string, options) => {\n return generateObject(\n text,\n {\n ...options,\n system: options.system || defaultSystemPrompt,\n },\n anthropic(options.model),\n )\n },\n output: 'text',\n settings: {\n name: `${MODEL_KEY}-object-settings`,\n type: 'group',\n admin: {\n condition(data) {\n return data['model-id'] === `${MODEL_KEY}-object`\n },\n },\n fields: [\n {\n name: 'model',\n type: 'select',\n defaultValue: 'claude-3-5-sonnet-latest',\n label: 'Model',\n options: MODELS,\n },\n {\n type: 'row',\n fields: [\n {\n name: 'maxTokens',\n type: 'number',\n defaultValue: 5000,\n },\n {\n name: 'temperature',\n type: 'number',\n defaultValue: 0.7,\n max: 1,\n min: 0,\n },\n ],\n },\n {\n name: 'extractAttachments',\n type: 'checkbox',\n },\n ],\n label: 'Anthropic Claude Settings',\n },\n },\n ],\n provider: 'Anthropic',\n}\n"],"names":["anthropic","defaultSystemPrompt","generateObject","MODEL_KEY","MODELS","AnthropicConfig","models","id","name","fields","handler","prompt","options","system","model","output","settings","type","admin","condition","data","defaultValue","label","max","min","text","provider"],"mappings":"AAAA,SAASA,SAAS,QAAQ,oBAAmB;AAI7C,SAASC,mBAAmB,QAAQ,mBAAkB;AACtD,SAASC,cAAc,QAAQ,uBAAsB;AAErD,MAAMC,YAAY;AAClB,MAAMC,SAAS;IACb;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,OAAO,MAAMC,kBAAoC;IAC/CC,QAAQ;QACN;YACEC,IAAI,CAAC,EAAEJ,UAAU,KAAK,CAAC;YACvBK,MAAM;YACNC,QAAQ;gBAAC;gBAAQ;aAAW;YAC5BC,SAAS,CACPC,QACAC;gBAUA,OAAOV,eACLS,QACA;oBACE,GAAGC,OAAO;oBACVC,QAAQD,QAAQC,MAAM,IAAIZ;gBAC5B,GACAD,UAAUY,QAAQE,KAAK;YAE3B;YACAC,QAAQ;YACRC,UAAU;gBACRR,MAAM,CAAC,EAAEL,UAAU,cAAc,CAAC;gBAClCc,MAAM;gBACNC,OAAO;oBACLC,WAAUC,IAAI;wBACZ,OAAOA,IAAI,CAAC,WAAW,KAAK,CAAC,EAAEjB,UAAU,KAAK,CAAC;oBACjD;gBACF;gBACAM,QAAQ;oBACN;wBACED,MAAM;wBACNS,MAAM;wBACNI,cAAc;wBACdC,OAAO;wBACPV,SAASR;oBACX;oBACA;wBACEa,MAAM;wBACNR,QAAQ;4BACN;gCACED,MAAM;gCACNS,MAAM;gCACNI,cAAc;4BAChB;4BACA;gCACEb,MAAM;gCACNS,MAAM;gCACNI,cAAc;gCACdE,KAAK;gCACLC,KAAK;4BACP;yBACD;oBACH;oBACA;wBACEhB,MAAM;wBACNS,MAAM;oBACR;iBACD;gBACDK,OAAO;YACT;QACF;QACA;YACEf,IAAI,CAAC,EAAEJ,UAAU,OAAO,CAAC;YACzBK,MAAM;YACNC,QAAQ;gBAAC;aAAW;YACpBC,SAAS,CAACe,MAAcb;gBACtB,OAAOV,eACLuB,MACA;oBACE,GAAGb,OAAO;oBACVC,QAAQD,QAAQC,MAAM,IAAIZ;gBAC5B,GACAD,UAAUY,QAAQE,KAAK;YAE3B;YACAC,QAAQ;YACRC,UAAU;gBACRR,MAAM,CAAC,EAAEL,UAAU,gBAAgB,CAAC;gBACpCc,MAAM;gBACNC,OAAO;oBACLC,WAAUC,IAAI;wBACZ,OAAOA,IAAI,CAAC,WAAW,KAAK,CAAC,EAAEjB,UAAU,OAAO,CAAC;oBACnD;gBACF;gBACAM,QAAQ;oBACN;wBACED,MAAM;wBACNS,MAAM;wBACNI,cAAc;wBACdC,OAAO;wBACPV,SAASR;oBACX;oBACA;wBACEa,MAAM;wBACNR,QAAQ;4BACN;gCACED,MAAM;gCACNS,MAAM;gCACNI,cAAc;4BAChB;4BACA;gCACEb,MAAM;gCACNS,MAAM;gCACNI,cAAc;gCACdE,KAAK;gCACLC,KAAK;4BACP;yBACD;oBACH;oBACA;wBACEhB,MAAM;wBACNS,MAAM;oBACR;iBACD;gBACDK,OAAO;YACT;QACF;KACD;IACDI,UAAU;AACZ,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ai/models/elevenLabs/index.ts"],"sourcesContent":["import type { Field, File } from 'payload'\n\nimport type { GenerationConfig } from '../../../types.js'\nimport type { Voice } from './voices.js'\n\nimport { generateFileNameByPrompt } from '../../utils/generateFileNameByPrompt.js'\nimport { generateVoice } from './generateVoice.js'\nimport { getAllVoices } from './voices.js'\n\nconst { voices = [] }: { voices: Voice[] } = await getAllVoices()\n\nconst voiceOptions = voices.map((voice) => {\n return {\n label: voice.name ?? '',\n value: voice.voice_id,\n ...voice,\n }\n})\n\nconst fieldVoiceOptions = voiceOptions.map((option) => {\n return {\n label: option.name ?? '',\n value: option.voice_id,\n }\n})\n\nconst fields: Field[] = [\n {\n type: 'collapsible',\n admin: {\n initCollapsed: false,\n },\n fields: [\n {\n name: 'stability',\n type: 'number',\n defaultValue: 0.5,\n label: 'Stability',\n max: 1,\n min: 0,\n required: true,\n },\n {\n name: 'similarity_boost',\n type: 'number',\n defaultValue: 0.5,\n label: 'Similarity Boost',\n max: 1,\n min: 0,\n required: true,\n },\n {\n name: 'style',\n type: 'number',\n defaultValue: 0.5,\n label: 'Style',\n max: 1,\n min: 0,\n },\n {\n name: 'use_speaker_boost',\n type: 'checkbox',\n label: 'Use Speaker Boost',\n },\n ],\n label: 'Voice Settings',\n },\n {\n name: 'seed',\n type: 'number',\n label: 'Seed',\n },\n {\n type: 'row',\n fields: [\n {\n name: 'previous_text',\n type: 'textarea',\n label: 'Previous Text',\n },\n {\n name: 'next_text',\n type: 'textarea',\n label: 'Next Text',\n },\n ],\n },\n]\n\nif (voiceOptions.length) {\n fields.unshift({\n name: 'voice_id',\n type: 'select',\n defaultValue: voiceOptions[0]?.voice_id,\n label: 'Voice',\n options: fieldVoiceOptions,\n required: true,\n })\n}\n\nconst MODEL_KEY = '11Labs'\n\nexport const ElevenLabsConfig: GenerationConfig = {\n models: [\n {\n id: `${MODEL_KEY}-m-v2`,\n name: 'ElevenLabs Multilingual v2',\n fields: ['upload'],\n handler: async (text: string, options) => {\n const voiceData = await generateVoice(text, options)\n if (!voiceData || !voiceData.buffer) {\n throw new Error('Voice data missing')\n }\n return {\n data: {\n alt: 'voice over',\n },\n file: {\n name: `voice_${generateFileNameByPrompt(text)}.mp3`,\n data: voiceData.buffer,\n mimetype: 'audio/mp3',\n size: voiceData.buffer.byteLength,\n } as File,\n }\n },\n output: 'audio',\n settings: {\n name: `${MODEL_KEY}-settings`,\n type: 'group',\n admin: {\n condition: (data) => {\n return data['model-id'] === `${MODEL_KEY}-m-v2`\n },\n },\n fields,\n label: 'ElevenLabs Multilingual v2 Settings',\n },\n },\n ],\n provider: 'ElevenLabs',\n}\n"],"names":["generateFileNameByPrompt","generateVoice","getAllVoices","voices","voiceOptions","map","voice","label","name","value","voice_id","fieldVoiceOptions","option","fields","type","admin","initCollapsed","defaultValue","max","min","required","length","unshift","options","MODEL_KEY","ElevenLabsConfig","models","id","handler","text","voiceData","buffer","Error","data","alt","file","mimetype","size","byteLength","output","settings","condition","provider"],"mappings":"AAKA,SAASA,wBAAwB,QAAQ,0CAAyC;AAClF,SAASC,aAAa,QAAQ,qBAAoB;AAClD,SAASC,YAAY,QAAQ,cAAa;AAE1C,MAAM,EAAEC,SAAS,EAAE,EAAE,GAAwB,MAAMD;AAEnD,MAAME,eAAeD,OAAOE,GAAG,CAAC,CAACC;IAC/B,OAAO;QACLC,OAAOD,MAAME,IAAI,IAAI;QACrBC,OAAOH,MAAMI,QAAQ;QACrB,GAAGJ,KAAK;IACV;AACF;AAEA,MAAMK,oBAAoBP,aAAaC,GAAG,CAAC,CAACO;IAC1C,OAAO;QACLL,OAAOK,OAAOJ,IAAI,IAAI;QACtBC,OAAOG,OAAOF,QAAQ;IACxB;AACF;AAEA,MAAMG,SAAkB;IACtB;QACEC,MAAM;QACNC,OAAO;YACLC,eAAe;QACjB;QACAH,QAAQ;YACN;gBACEL,MAAM;gBACNM,MAAM;gBACNG,cAAc;gBACdV,OAAO;gBACPW,KAAK;gBACLC,KAAK;gBACLC,UAAU;YACZ;YACA;gBACEZ,MAAM;gBACNM,MAAM;gBACNG,cAAc;gBACdV,OAAO;gBACPW,KAAK;gBACLC,KAAK;gBACLC,UAAU;YACZ;YACA;gBACEZ,MAAM;gBACNM,MAAM;gBACNG,cAAc;gBACdV,OAAO;gBACPW,KAAK;gBACLC,KAAK;YACP;YACA;gBACEX,MAAM;gBACNM,MAAM;gBACNP,OAAO;YACT;SACD;QACDA,OAAO;IACT;IACA;QACEC,MAAM;QACNM,MAAM;QACNP,OAAO;IACT;IACA;QACEO,MAAM;QACND,QAAQ;YACN;gBACEL,MAAM;gBACNM,MAAM;gBACNP,OAAO;YACT;YACA;gBACEC,MAAM;gBACNM,MAAM;gBACNP,OAAO;YACT;SACD;IACH;CACD;AAED,IAAIH,aAAaiB,MAAM,EAAE;IACvBR,OAAOS,OAAO,CAAC;QACbd,MAAM;QACNM,MAAM;QACNG,cAAcb,YAAY,CAAC,EAAE,EAAEM;QAC/BH,OAAO;QACPgB,SAASZ;QACTS,UAAU;IACZ;AACF;AAEA,MAAMI,YAAY;AAElB,OAAO,MAAMC,mBAAqC;IAChDC,QAAQ;QACN;YACEC,IAAI,
|
|
1
|
+
{"version":3,"sources":["../../../../src/ai/models/elevenLabs/index.ts"],"sourcesContent":["import type { Field, File } from 'payload'\n\nimport type { GenerationConfig } from '../../../types.js'\nimport type { Voice } from './voices.js'\n\nimport { generateFileNameByPrompt } from '../../utils/generateFileNameByPrompt.js'\nimport { generateVoice } from './generateVoice.js'\nimport { getAllVoices } from './voices.js'\n\nconst { voices = [] }: { voices: Voice[] } = await getAllVoices()\n\nconst voiceOptions = voices.map((voice) => {\n return {\n label: voice.name ?? '',\n value: voice.voice_id,\n ...voice,\n }\n})\n\nconst fieldVoiceOptions = voiceOptions.map((option) => {\n return {\n label: option.name ?? '',\n value: option.voice_id,\n }\n})\n\nconst fields: Field[] = [\n {\n type: 'collapsible',\n admin: {\n initCollapsed: false,\n },\n fields: [\n {\n name: 'stability',\n type: 'number',\n defaultValue: 0.5,\n label: 'Stability',\n max: 1,\n min: 0,\n required: true,\n },\n {\n name: 'similarity_boost',\n type: 'number',\n defaultValue: 0.5,\n label: 'Similarity Boost',\n max: 1,\n min: 0,\n required: true,\n },\n {\n name: 'style',\n type: 'number',\n defaultValue: 0.5,\n label: 'Style',\n max: 1,\n min: 0,\n },\n {\n name: 'use_speaker_boost',\n type: 'checkbox',\n label: 'Use Speaker Boost',\n },\n ],\n label: 'Voice Settings',\n },\n {\n name: 'seed',\n type: 'number',\n label: 'Seed',\n },\n {\n type: 'row',\n fields: [\n {\n name: 'previous_text',\n type: 'textarea',\n label: 'Previous Text',\n },\n {\n name: 'next_text',\n type: 'textarea',\n label: 'Next Text',\n },\n ],\n },\n]\n\nif (voiceOptions.length) {\n fields.unshift({\n name: 'voice_id',\n type: 'select',\n defaultValue: voiceOptions[0]?.voice_id,\n label: 'Voice',\n options: fieldVoiceOptions,\n required: true,\n })\n}\n\nconst MODEL_KEY = '11Labs'\n\nexport const ElevenLabsConfig: GenerationConfig = {\n models: [\n {\n id: `${MODEL_KEY}-m-v2`,\n name: 'ElevenLabs Multilingual v2',\n fields: ['upload'],\n handler: async (text: string, options) => {\n const voiceData = await generateVoice(text, options)\n if (!voiceData || !voiceData.buffer) {\n throw new Error('Voice data missing')\n }\n return {\n data: {\n alt: 'voice over',\n },\n file: {\n name: `voice_${generateFileNameByPrompt(text)}.mp3`,\n data: voiceData.buffer,\n mimetype: 'audio/mp3',\n size: voiceData.buffer.byteLength,\n } as File,\n }\n },\n output: 'audio',\n settings: {\n name: `${MODEL_KEY}-settings`,\n type: 'group',\n admin: {\n condition: (data) => {\n return data['model-id'] === `${MODEL_KEY}-m-v2`\n },\n },\n fields,\n label: 'ElevenLabs Multilingual v2 Settings',\n },\n },\n ],\n provider: 'ElevenLabs',\n}\n"],"names":["generateFileNameByPrompt","generateVoice","getAllVoices","voices","voiceOptions","map","voice","label","name","value","voice_id","fieldVoiceOptions","option","fields","type","admin","initCollapsed","defaultValue","max","min","required","length","unshift","options","MODEL_KEY","ElevenLabsConfig","models","id","handler","text","voiceData","buffer","Error","data","alt","file","mimetype","size","byteLength","output","settings","condition","provider"],"mappings":"AAKA,SAASA,wBAAwB,QAAQ,0CAAyC;AAClF,SAASC,aAAa,QAAQ,qBAAoB;AAClD,SAASC,YAAY,QAAQ,cAAa;AAE1C,MAAM,EAAEC,SAAS,EAAE,EAAE,GAAwB,MAAMD;AAEnD,MAAME,eAAeD,OAAOE,GAAG,CAAC,CAACC;IAC/B,OAAO;QACLC,OAAOD,MAAME,IAAI,IAAI;QACrBC,OAAOH,MAAMI,QAAQ;QACrB,GAAGJ,KAAK;IACV;AACF;AAEA,MAAMK,oBAAoBP,aAAaC,GAAG,CAAC,CAACO;IAC1C,OAAO;QACLL,OAAOK,OAAOJ,IAAI,IAAI;QACtBC,OAAOG,OAAOF,QAAQ;IACxB;AACF;AAEA,MAAMG,SAAkB;IACtB;QACEC,MAAM;QACNC,OAAO;YACLC,eAAe;QACjB;QACAH,QAAQ;YACN;gBACEL,MAAM;gBACNM,MAAM;gBACNG,cAAc;gBACdV,OAAO;gBACPW,KAAK;gBACLC,KAAK;gBACLC,UAAU;YACZ;YACA;gBACEZ,MAAM;gBACNM,MAAM;gBACNG,cAAc;gBACdV,OAAO;gBACPW,KAAK;gBACLC,KAAK;gBACLC,UAAU;YACZ;YACA;gBACEZ,MAAM;gBACNM,MAAM;gBACNG,cAAc;gBACdV,OAAO;gBACPW,KAAK;gBACLC,KAAK;YACP;YACA;gBACEX,MAAM;gBACNM,MAAM;gBACNP,OAAO;YACT;SACD;QACDA,OAAO;IACT;IACA;QACEC,MAAM;QACNM,MAAM;QACNP,OAAO;IACT;IACA;QACEO,MAAM;QACND,QAAQ;YACN;gBACEL,MAAM;gBACNM,MAAM;gBACNP,OAAO;YACT;YACA;gBACEC,MAAM;gBACNM,MAAM;gBACNP,OAAO;YACT;SACD;IACH;CACD;AAED,IAAIH,aAAaiB,MAAM,EAAE;IACvBR,OAAOS,OAAO,CAAC;QACbd,MAAM;QACNM,MAAM;QACNG,cAAcb,YAAY,CAAC,EAAE,EAAEM;QAC/BH,OAAO;QACPgB,SAASZ;QACTS,UAAU;IACZ;AACF;AAEA,MAAMI,YAAY;AAElB,OAAO,MAAMC,mBAAqC;IAChDC,QAAQ;QACN;YACEC,IAAI,CAAC,EAAEH,UAAU,KAAK,CAAC;YACvBhB,MAAM;YACNK,QAAQ;gBAAC;aAAS;YAClBe,SAAS,OAAOC,MAAcN;gBAC5B,MAAMO,YAAY,MAAM7B,cAAc4B,MAAMN;gBAC5C,IAAI,CAACO,aAAa,CAACA,UAAUC,MAAM,EAAE;oBACnC,MAAM,IAAIC,MAAM;gBAClB;gBACA,OAAO;oBACLC,MAAM;wBACJC,KAAK;oBACP;oBACAC,MAAM;wBACJ3B,MAAM,CAAC,MAAM,EAAER,yBAAyB6B,MAAM,IAAI,CAAC;wBACnDI,MAAMH,UAAUC,MAAM;wBACtBK,UAAU;wBACVC,MAAMP,UAAUC,MAAM,CAACO,UAAU;oBACnC;gBACF;YACF;YACAC,QAAQ;YACRC,UAAU;gBACRhC,MAAM,CAAC,EAAEgB,UAAU,SAAS,CAAC;gBAC7BV,MAAM;gBACNC,OAAO;oBACL0B,WAAW,CAACR;wBACV,OAAOA,IAAI,CAAC,WAAW,KAAK,CAAC,EAAET,UAAU,KAAK,CAAC;oBACjD;gBACF;gBACAX;gBACAN,OAAO;YACT;QACF;KACD;IACDmC,UAAU;AACZ,EAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GenerateImageParams } from '../../../types.js';
|
|
2
|
+
export declare const generateImage: (prompt: string, { aspectRatio, model, outputMimeType, }?: GenerateImageParams & {
|
|
3
|
+
aspectRatio?: "1:1" | "3:4" | "4:3" | "9:16" | "16:9";
|
|
4
|
+
model?: string;
|
|
5
|
+
outputMimeType?: "image/jpeg" | "image/png";
|
|
6
|
+
}) => Promise<{
|
|
7
|
+
alt: string;
|
|
8
|
+
buffer: Buffer<ArrayBuffer>;
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { GoogleGenAI } from '@google/genai';
|
|
2
|
+
export const generateImage = async (prompt, { aspectRatio = '1:1', model = 'imagen-4.0-fast-generate-001', outputMimeType = 'image/png' } = {})=>{
|
|
3
|
+
const ai = new GoogleGenAI({
|
|
4
|
+
apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY
|
|
5
|
+
});
|
|
6
|
+
const response = await ai.models.generateImages({
|
|
7
|
+
model,
|
|
8
|
+
prompt,
|
|
9
|
+
config: {
|
|
10
|
+
numberOfImages: 1,
|
|
11
|
+
aspectRatio,
|
|
12
|
+
outputMimeType
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
const generatedImage = response.generatedImages?.[0];
|
|
16
|
+
if (!generatedImage?.image?.imageBytes) {
|
|
17
|
+
throw new Error('No image generated');
|
|
18
|
+
}
|
|
19
|
+
const base64ImageBytes = generatedImage.image.imageBytes;
|
|
20
|
+
const buffer = Buffer.from(base64ImageBytes, 'base64');
|
|
21
|
+
return {
|
|
22
|
+
alt: generatedImage.enhancedPrompt || prompt,
|
|
23
|
+
buffer
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=generateImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/ai/models/google/generateImage.ts"],"sourcesContent":["import { GoogleGenAI } from '@google/genai'\n\nimport type { GenerateImageParams } from '../../../types.js'\n\nexport const generateImage = async (\n prompt: string,\n {\n aspectRatio = '1:1',\n model = 'imagen-4.0-fast-generate-001',\n outputMimeType = 'image/png',\n }: GenerateImageParams & {\n aspectRatio?: '1:1' | '3:4' | '4:3' | '9:16' | '16:9'\n model?: string\n outputMimeType?: 'image/jpeg' | 'image/png'\n } = {},\n) => {\n const ai = new GoogleGenAI({\n apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,\n })\n\n const response = await ai.models.generateImages({\n model,\n prompt,\n config: {\n numberOfImages: 1,\n aspectRatio,\n outputMimeType,\n },\n })\n\n const generatedImage = response.generatedImages?.[0]\n if (!generatedImage?.image?.imageBytes) {\n throw new Error('No image generated')\n }\n\n const base64ImageBytes = generatedImage.image.imageBytes\n const buffer = Buffer.from(base64ImageBytes, 'base64')\n\n return {\n alt: generatedImage.enhancedPrompt || prompt,\n buffer,\n }\n}\n\n"],"names":["GoogleGenAI","generateImage","prompt","aspectRatio","model","outputMimeType","ai","apiKey","process","env","GOOGLE_GENERATIVE_AI_API_KEY","response","models","generateImages","config","numberOfImages","generatedImage","generatedImages","image","imageBytes","Error","base64ImageBytes","buffer","Buffer","from","alt","enhancedPrompt"],"mappings":"AAAA,SAASA,WAAW,QAAQ,gBAAe;AAI3C,OAAO,MAAMC,gBAAgB,OAC3BC,QACA,EACEC,cAAc,KAAK,EACnBC,QAAQ,8BAA8B,EACtCC,iBAAiB,WAAW,EAK7B,GAAG,CAAC,CAAC;IAEN,MAAMC,KAAK,IAAIN,YAAY;QACzBO,QAAQC,QAAQC,GAAG,CAACC,4BAA4B;IAClD;IAEA,MAAMC,WAAW,MAAML,GAAGM,MAAM,CAACC,cAAc,CAAC;QAC9CT;QACAF;QACAY,QAAQ;YACNC,gBAAgB;YAChBZ;YACAE;QACF;IACF;IAEA,MAAMW,iBAAiBL,SAASM,eAAe,EAAE,CAAC,EAAE;IACpD,IAAI,CAACD,gBAAgBE,OAAOC,YAAY;QACtC,MAAM,IAAIC,MAAM;IAClB;IAEA,MAAMC,mBAAmBL,eAAeE,KAAK,CAACC,UAAU;IACxD,MAAMG,SAASC,OAAOC,IAAI,CAACH,kBAAkB;IAE7C,OAAO;QACLI,KAAKT,eAAeU,cAAc,IAAIxB;QACtCoB;IACF;AACF,EAAC"}
|