@ai-stack/payloadcms 3.2.24-beta → 3.68.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.
Files changed (284) hide show
  1. package/{LICENSE.md → LICENSE} +1 -1
  2. package/README.md +218 -229
  3. package/dist/access/checkAccess.d.ts +4 -0
  4. package/dist/access/checkAccess.js +20 -0
  5. package/dist/access/checkAccess.js.map +1 -0
  6. package/dist/ai/core/generateObject.d.ts +7 -0
  7. package/dist/ai/core/generateObject.js +35 -0
  8. package/dist/ai/core/generateObject.js.map +1 -0
  9. package/dist/ai/core/generateText.d.ts +7 -0
  10. package/dist/ai/core/generateText.js +31 -0
  11. package/dist/ai/core/generateText.js.map +1 -0
  12. package/dist/ai/core/index.d.ts +11 -0
  13. package/dist/ai/core/index.js +10 -0
  14. package/dist/ai/core/index.js.map +1 -0
  15. package/dist/ai/core/media/generateMedia.d.ts +7 -0
  16. package/dist/ai/core/media/generateMedia.js +50 -0
  17. package/dist/ai/core/media/generateMedia.js.map +1 -0
  18. package/dist/ai/core/media/image/generateImage.d.ts +6 -0
  19. package/dist/ai/core/media/image/generateImage.js +41 -0
  20. package/dist/ai/core/media/image/generateImage.js.map +1 -0
  21. package/dist/ai/core/media/image/handlers/multimodal.d.ts +7 -0
  22. package/dist/ai/core/media/image/handlers/multimodal.js +95 -0
  23. package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -0
  24. package/dist/ai/core/media/image/handlers/standard.d.ts +7 -0
  25. package/dist/ai/core/media/image/handlers/standard.js +28 -0
  26. package/dist/ai/core/media/image/handlers/standard.js.map +1 -0
  27. package/dist/ai/core/media/image/index.d.ts +2 -0
  28. package/dist/ai/core/media/image/index.js +3 -0
  29. package/dist/ai/core/media/image/index.js.map +1 -0
  30. package/dist/ai/core/media/index.d.ts +2 -0
  31. package/dist/ai/core/media/index.js +3 -0
  32. package/dist/ai/core/media/index.js.map +1 -0
  33. package/dist/ai/core/media/speech/generateSpeech.d.ts +5 -0
  34. package/dist/ai/core/media/speech/generateSpeech.js +55 -0
  35. package/dist/ai/core/media/speech/generateSpeech.js.map +1 -0
  36. package/dist/ai/core/media/speech/index.d.ts +2 -0
  37. package/dist/ai/core/media/speech/index.js +3 -0
  38. package/dist/ai/core/media/speech/index.js.map +1 -0
  39. package/dist/ai/core/media/types.d.ts +74 -0
  40. package/dist/ai/core/media/types.js +5 -0
  41. package/dist/ai/core/media/types.js.map +1 -0
  42. package/dist/ai/core/media/utils.d.ts +11 -0
  43. package/dist/ai/core/media/utils.js +34 -0
  44. package/dist/ai/core/media/utils.js.map +1 -0
  45. package/dist/ai/core/media/video/generateVideo.d.ts +6 -0
  46. package/dist/ai/core/media/video/generateVideo.js +32 -0
  47. package/dist/ai/core/media/video/generateVideo.js.map +1 -0
  48. package/dist/ai/core/media/video/index.d.ts +2 -0
  49. package/dist/ai/core/media/video/index.js +3 -0
  50. package/dist/ai/core/media/video/index.js.map +1 -0
  51. package/dist/ai/core/streamObject.d.ts +7 -0
  52. package/dist/ai/core/streamObject.js +57 -0
  53. package/dist/ai/core/streamObject.js.map +1 -0
  54. package/dist/ai/core/streamText.d.ts +7 -0
  55. package/dist/ai/core/streamText.js +30 -0
  56. package/dist/ai/core/streamText.js.map +1 -0
  57. package/dist/ai/core/types.d.ts +85 -0
  58. package/dist/ai/core/types.js +5 -0
  59. package/dist/ai/core/types.js.map +1 -0
  60. package/dist/ai/index.d.ts +11 -0
  61. package/dist/ai/index.js +25 -0
  62. package/dist/ai/index.js.map +1 -0
  63. package/dist/ai/providers/blocks/anthropic.d.ts +2 -0
  64. package/dist/ai/providers/blocks/anthropic.js +222 -0
  65. package/dist/ai/providers/blocks/anthropic.js.map +1 -0
  66. package/dist/ai/providers/blocks/elevenlabs.d.ts +2 -0
  67. package/dist/ai/providers/blocks/elevenlabs.js +448 -0
  68. package/dist/ai/providers/blocks/elevenlabs.js.map +1 -0
  69. package/dist/ai/providers/blocks/fal.d.ts +2 -0
  70. package/dist/ai/providers/blocks/fal.js +311 -0
  71. package/dist/ai/providers/blocks/fal.js.map +1 -0
  72. package/dist/ai/providers/blocks/google.d.ts +2 -0
  73. package/dist/ai/providers/blocks/google.js +622 -0
  74. package/dist/ai/providers/blocks/google.js.map +1 -0
  75. package/dist/ai/providers/blocks/index.d.ts +2 -0
  76. package/dist/ai/providers/blocks/index.js +18 -0
  77. package/dist/ai/providers/blocks/index.js.map +1 -0
  78. package/dist/ai/providers/blocks/openai-compatible.d.ts +2 -0
  79. package/dist/ai/providers/blocks/openai-compatible.js +307 -0
  80. package/dist/ai/providers/blocks/openai-compatible.js.map +1 -0
  81. package/dist/ai/providers/blocks/openai.d.ts +2 -0
  82. package/dist/ai/providers/blocks/openai.js +599 -0
  83. package/dist/ai/providers/blocks/openai.js.map +1 -0
  84. package/dist/ai/providers/blocks/xai.d.ts +2 -0
  85. package/dist/ai/providers/blocks/xai.js +246 -0
  86. package/dist/ai/providers/blocks/xai.js.map +1 -0
  87. package/dist/ai/providers/index.d.ts +2 -0
  88. package/dist/ai/providers/index.js +6 -0
  89. package/dist/ai/providers/index.js.map +1 -0
  90. package/dist/ai/providers/registry.d.ts +40 -0
  91. package/dist/ai/providers/registry.js +256 -0
  92. package/dist/ai/providers/registry.js.map +1 -0
  93. package/dist/ai/providers/types.d.ts +115 -0
  94. package/dist/ai/providers/types.js +4 -0
  95. package/dist/ai/providers/types.js.map +1 -0
  96. package/dist/ai/utils/systemGenerate.d.ts +1 -1
  97. package/dist/ai/utils/systemGenerate.js +19 -19
  98. package/dist/ai/utils/systemGenerate.js.map +1 -1
  99. package/dist/collections/AIJobs.d.ts +2 -0
  100. package/dist/collections/AIJobs.js +81 -0
  101. package/dist/collections/AIJobs.js.map +1 -0
  102. package/dist/collections/AISettings.d.ts +2 -0
  103. package/dist/collections/AISettings.js +279 -0
  104. package/dist/collections/AISettings.js.map +1 -0
  105. package/dist/collections/Instructions.js +185 -37
  106. package/dist/collections/Instructions.js.map +1 -1
  107. package/dist/defaults.d.ts +3 -0
  108. package/dist/defaults.js +3 -0
  109. package/dist/defaults.js.map +1 -1
  110. package/dist/endpoints/buildPromptUtils.d.ts +19 -0
  111. package/dist/endpoints/buildPromptUtils.js +114 -0
  112. package/dist/endpoints/buildPromptUtils.js.map +1 -0
  113. package/dist/endpoints/chat.d.js +3 -0
  114. package/dist/endpoints/chat.d.js.map +1 -0
  115. package/dist/endpoints/fetchVoices.d.ts +2 -0
  116. package/dist/endpoints/fetchVoices.js +79 -0
  117. package/dist/endpoints/fetchVoices.js.map +1 -0
  118. package/dist/endpoints/index.js +253 -214
  119. package/dist/endpoints/index.js.map +1 -1
  120. package/dist/exports/client.d.ts +9 -0
  121. package/dist/exports/client.js +9 -0
  122. package/dist/exports/client.js.map +1 -1
  123. package/dist/fields/ComposeField/ComposeField.js +2 -2
  124. package/dist/fields/ComposeField/ComposeField.js.map +1 -1
  125. package/dist/fields/ComposeField/ComposeField.jsx +2 -2
  126. package/dist/fields/PromptEditorField/PromptEditorField.js +155 -14
  127. package/dist/fields/PromptEditorField/PromptEditorField.js.map +1 -1
  128. package/dist/fields/PromptEditorField/PromptEditorField.jsx +118 -3
  129. package/dist/index.d.ts +1 -0
  130. package/dist/index.js.map +1 -1
  131. package/dist/init.js +35 -13
  132. package/dist/init.js.map +1 -1
  133. package/dist/payload-ai.d.js +3 -0
  134. package/dist/payload-ai.d.js.map +1 -0
  135. package/dist/plugin.js +80 -9
  136. package/dist/plugin.js.map +1 -1
  137. package/dist/providers/InstructionsProvider/InstructionsProvider.js +35 -7
  138. package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
  139. package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +27 -4
  140. package/dist/providers/InstructionsProvider/context.d.ts +1 -0
  141. package/dist/providers/InstructionsProvider/context.js +1 -0
  142. package/dist/providers/InstructionsProvider/context.js.map +1 -1
  143. package/dist/providers/InstructionsProvider/useInstructions.js +13 -6
  144. package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
  145. package/dist/types.d.ts +7 -7
  146. package/dist/types.js.map +1 -1
  147. package/dist/ui/AIConfigDashboard/index.d.ts +2 -0
  148. package/dist/ui/AIConfigDashboard/index.js +46 -0
  149. package/dist/ui/AIConfigDashboard/index.js.map +1 -0
  150. package/dist/ui/AIConfigDashboard/index.jsx +24 -0
  151. package/dist/ui/ApiKeyStatusIndicator/index.d.ts +6 -0
  152. package/dist/ui/ApiKeyStatusIndicator/index.js +39 -0
  153. package/dist/ui/ApiKeyStatusIndicator/index.js.map +1 -0
  154. package/dist/ui/ApiKeyStatusIndicator/index.jsx +29 -0
  155. package/dist/ui/Compose/Compose.d.ts +1 -2
  156. package/dist/ui/Compose/Compose.js +116 -90
  157. package/dist/ui/Compose/Compose.js.map +1 -1
  158. package/dist/ui/Compose/Compose.jsx +111 -101
  159. package/dist/ui/Compose/ComposePlaceholder.d.ts +7 -0
  160. package/dist/ui/Compose/ComposePlaceholder.js +78 -0
  161. package/dist/ui/Compose/ComposePlaceholder.js.map +1 -0
  162. package/dist/ui/Compose/ComposePlaceholder.jsx +66 -0
  163. package/dist/ui/Compose/UndoRedoActions.js +3 -1
  164. package/dist/ui/Compose/UndoRedoActions.js.map +1 -1
  165. package/dist/ui/Compose/UndoRedoActions.jsx +2 -1
  166. package/dist/ui/Compose/compose.module.css +1 -1
  167. package/dist/ui/Compose/hooks/menu/itemsMap.js +1 -1
  168. package/dist/ui/Compose/hooks/menu/itemsMap.js.map +1 -1
  169. package/dist/ui/Compose/hooks/menu/useMenu.d.ts +2 -1
  170. package/dist/ui/Compose/hooks/menu/useMenu.js +2 -2
  171. package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
  172. package/dist/ui/Compose/hooks/menu/useMenu.jsx +2 -2
  173. package/dist/ui/Compose/hooks/useActiveFieldTracking.js +69 -10
  174. package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -1
  175. package/dist/ui/Compose/hooks/useGenerate.d.ts +3 -0
  176. package/dist/ui/Compose/hooks/useGenerate.js +71 -11
  177. package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
  178. package/dist/ui/Compose/hooks/useHistory.js +52 -5
  179. package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
  180. package/dist/ui/DynamicModelSelect/index.d.ts +7 -0
  181. package/dist/ui/DynamicModelSelect/index.js +231 -0
  182. package/dist/ui/DynamicModelSelect/index.js.map +1 -0
  183. package/dist/ui/DynamicModelSelect/index.jsx +207 -0
  184. package/dist/ui/DynamicProviderSelect/index.d.ts +7 -0
  185. package/dist/ui/DynamicProviderSelect/index.js +101 -0
  186. package/dist/ui/DynamicProviderSelect/index.js.map +1 -0
  187. package/dist/ui/DynamicProviderSelect/index.jsx +90 -0
  188. package/dist/ui/DynamicVoiceSelect/index.d.ts +7 -0
  189. package/dist/ui/DynamicVoiceSelect/index.js +104 -0
  190. package/dist/ui/DynamicVoiceSelect/index.js.map +1 -0
  191. package/dist/ui/DynamicVoiceSelect/index.jsx +69 -0
  192. package/dist/ui/EncryptedTextField/index.d.ts +8 -0
  193. package/dist/ui/EncryptedTextField/index.js +74 -0
  194. package/dist/ui/EncryptedTextField/index.js.map +1 -0
  195. package/dist/ui/EncryptedTextField/index.jsx +35 -0
  196. package/dist/ui/Icons/LottieAnimation.js +3 -1
  197. package/dist/ui/Icons/LottieAnimation.js.map +1 -1
  198. package/dist/ui/Icons/LottieAnimation.jsx +2 -1
  199. package/dist/ui/ModelRowLabel/index.d.ts +6 -0
  200. package/dist/ui/ModelRowLabel/index.js +41 -0
  201. package/dist/ui/ModelRowLabel/index.js.map +1 -0
  202. package/dist/ui/ModelRowLabel/index.jsx +26 -0
  203. package/dist/ui/ProviderOptionsEditor/index.d.ts +7 -0
  204. package/dist/ui/ProviderOptionsEditor/index.js +291 -0
  205. package/dist/ui/ProviderOptionsEditor/index.js.map +1 -0
  206. package/dist/ui/ProviderOptionsEditor/index.jsx +210 -0
  207. package/dist/ui/VoicesFetcher/index.d.ts +7 -0
  208. package/dist/ui/VoicesFetcher/index.js +72 -0
  209. package/dist/ui/VoicesFetcher/index.js.map +1 -0
  210. package/dist/ui/VoicesFetcher/index.jsx +56 -0
  211. package/dist/utilities/encryption.d.ts +2 -0
  212. package/dist/utilities/encryption.js +47 -0
  213. package/dist/utilities/encryption.js.map +1 -0
  214. package/dist/utilities/extractImageData.d.ts +9 -0
  215. package/dist/utilities/extractImageData.js +12 -2
  216. package/dist/utilities/extractImageData.js.map +1 -1
  217. package/dist/utilities/fetchImages.d.ts +14 -0
  218. package/dist/utilities/fetchImages.js +38 -0
  219. package/dist/utilities/fetchImages.js.map +1 -0
  220. package/dist/utilities/fieldToJsonSchema.d.ts +2 -1
  221. package/dist/utilities/fieldToJsonSchema.js +66 -3
  222. package/dist/utilities/fieldToJsonSchema.js.map +1 -1
  223. package/dist/utilities/getFieldBySchemaPath.js +15 -0
  224. package/dist/utilities/getFieldBySchemaPath.js.map +1 -1
  225. package/dist/utilities/getProviderOptionsFields.d.ts +16 -0
  226. package/dist/utilities/getProviderOptionsFields.js +80 -0
  227. package/dist/utilities/getProviderOptionsFields.js.map +1 -0
  228. package/dist/utilities/isPluginActivated.js +1 -2
  229. package/dist/utilities/isPluginActivated.js.map +1 -1
  230. package/dist/utilities/lexicalToHTML.js.map +1 -1
  231. package/dist/utilities/resolveImageReferences.d.ts +28 -0
  232. package/dist/utilities/resolveImageReferences.js +148 -0
  233. package/dist/utilities/resolveImageReferences.js.map +1 -0
  234. package/dist/utilities/schemaConverter.d.ts +3 -0
  235. package/dist/utilities/schemaConverter.js +93 -0
  236. package/dist/utilities/schemaConverter.js.map +1 -0
  237. package/dist/utilities/setSafeLexicalState.d.ts +1 -3
  238. package/dist/utilities/setSafeLexicalState.js +1 -1
  239. package/dist/utilities/setSafeLexicalState.js.map +1 -1
  240. package/package.json +38 -39
  241. package/dist/ai/models/anthropic/index.d.ts +0 -2
  242. package/dist/ai/models/anthropic/index.js +0 -129
  243. package/dist/ai/models/anthropic/index.js.map +0 -1
  244. package/dist/ai/models/elevenLabs/generateVoice.d.ts +0 -8
  245. package/dist/ai/models/elevenLabs/generateVoice.js +0 -20
  246. package/dist/ai/models/elevenLabs/generateVoice.js.map +0 -1
  247. package/dist/ai/models/elevenLabs/index.d.ts +0 -2
  248. package/dist/ai/models/elevenLabs/index.js +0 -133
  249. package/dist/ai/models/elevenLabs/index.js.map +0 -1
  250. package/dist/ai/models/elevenLabs/voices.d.ts +0 -8
  251. package/dist/ai/models/elevenLabs/voices.js +0 -24
  252. package/dist/ai/models/elevenLabs/voices.js.map +0 -1
  253. package/dist/ai/models/generateObject.d.ts +0 -11
  254. package/dist/ai/models/generateObject.js +0 -22
  255. package/dist/ai/models/generateObject.js.map +0 -1
  256. package/dist/ai/models/google/generateImage.d.ts +0 -9
  257. package/dist/ai/models/google/generateImage.js +0 -27
  258. package/dist/ai/models/google/generateImage.js.map +0 -1
  259. package/dist/ai/models/google/index.d.ts +0 -2
  260. package/dist/ai/models/google/index.js +0 -201
  261. package/dist/ai/models/google/index.js.map +0 -1
  262. package/dist/ai/models/index.d.ts +0 -2
  263. package/dist/ai/models/index.js +0 -13
  264. package/dist/ai/models/index.js.map +0 -1
  265. package/dist/ai/models/openai/generateImage.d.ts +0 -5
  266. package/dist/ai/models/openai/generateImage.js +0 -31
  267. package/dist/ai/models/openai/generateImage.js.map +0 -1
  268. package/dist/ai/models/openai/generateVoice.d.ts +0 -6
  269. package/dist/ai/models/openai/generateVoice.js +0 -19
  270. package/dist/ai/models/openai/generateVoice.js.map +0 -1
  271. package/dist/ai/models/openai/index.d.ts +0 -2
  272. package/dist/ai/models/openai/index.js +0 -428
  273. package/dist/ai/models/openai/index.js.map +0 -1
  274. package/dist/ai/models/openai/openai.d.ts +0 -1
  275. package/dist/ai/models/openai/openai.js +0 -8
  276. package/dist/ai/models/openai/openai.js.map +0 -1
  277. package/dist/ai/utils/editImagesWithOpenAI.d.ts +0 -10
  278. package/dist/ai/utils/editImagesWithOpenAI.js +0 -37
  279. package/dist/ai/utils/editImagesWithOpenAI.js.map +0 -1
  280. package/dist/types.d.js +0 -3
  281. package/dist/types.d.js.map +0 -1
  282. package/dist/utilities/getGenerationModels.d.ts +0 -2
  283. package/dist/utilities/getGenerationModels.js +0 -10
  284. package/dist/utilities/getGenerationModels.js.map +0 -1
@@ -1,4 +1,4 @@
1
- ## 1. MIT License
1
+ MIT License
2
2
 
3
3
  Copyright (c) 2024 Ashish Mishra
4
4
 
package/README.md CHANGED
@@ -5,69 +5,75 @@
5
5
  </p>
6
6
 
7
7
  <p align="center">
8
- <strong>Transform content creation with intelligent automation your models, your way</strong>
8
+ <strong>Transform your Payload CMS into an AI-powered content powerhouse</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <img alt="Supported AI Providers" src="assets/providers.png" width="100%" />
12
+ <a href="https://www.npmjs.com/package/@ai-stack/payloadcms"><img src="https://img.shields.io/npm/v/@ai-stack/payloadcms.svg" alt="npm version"></a>
13
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/ashbuilds/payload-ai" alt="License"></a>
14
+ <a href="https://discord.com/channels/967097582721572934/1264949995656843345"><img src="https://img.shields.io/badge/discord-join-7289DA.svg" alt="Discord"></a>
13
15
  </p>
14
16
 
15
17
  ---
16
18
 
17
- ## 🚀 What is this?
19
+ ## Why Payload AI?
18
20
 
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.
21
+ **Stop context-switching between your CMS and AI tools.** The Payload AI Plugin brings the power of OpenAI, Anthropic, Google Gemini, xAI Grok, ElevenLabs, and more directly into your editing experience—no external apps, no copy-pasting, no friction.
20
22
 
21
- ### 🎥 See It in Action
23
+ Whether you're generating blog posts, creating product images, translating content, or building custom AI workflows, this plugin puts everything at your fingertips.
22
24
 
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
25
+ > **💡 New in this release:** Programmatic `payload.ai` API, multimodal image generation with Gemini, vision model support, and 7 AI providers!
26
26
 
27
27
  ---
28
28
 
29
- ## ⚠️ Beta Notice
29
+ ### 🎥 [Watch the Magic in Action](https://youtu.be/qaYukeGpuu4) | [Extended Demo](https://youtu.be/LEsuHbKalNY) | [Setup Guide](guide.md)
30
30
 
31
- This plugin is actively evolving. We're constantly shipping improvements and new features. Tested with Payload v3.38.0.
31
+ ---
32
32
 
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.
33
+ ## What Can You Do?
34
34
 
35
- ---
35
+ ### 📝 Text & Rich Text Generation
36
36
 
37
- ## Features
37
+ | Feature | Status | Description |
38
+ | ------------- | ------ | ---------------------------------------------- |
39
+ | **Compose** | ✅ | Generate content from natural language prompts |
40
+ | **Proofread** | ✅ | Fix grammar, spelling, and style issues |
41
+ | **Translate** | ✅ | Translate to 100+ languages |
42
+ | **Rephrase** | ✅ | Rewrite for different tones and audiences |
43
+ | **Expand** | 🔜 | Elaborate on existing content |
44
+ | **Summarize** | 🔜 | Condense long-form content |
38
45
 
39
- ### 📝 Text & RichText Fields
46
+ ### 🖼️ Image Generation
40
47
 
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
48
+ - **DALL-E 3** and **GPT-Image-1** from OpenAI
49
+ - **Imagen 3** from Google
50
+ - **Gemini 2.5 Flash** multimodal image generation
51
+ - **FAL** for fast, high-quality images
52
+ - Reference existing images with `@fieldName` syntax for variations
49
53
 
50
- ### 🎨 Upload Fields
54
+ ### 🎙️ Voice Generation (Text-to-Speech)
51
55
 
52
- - 🎙️ **Voice Generation** - Powered by ElevenLabs & OpenAI
53
- - 🖼️ **Image Generation** - Powered by OpenAI (DALL-E & GPT-Image-1)
56
+ - **ElevenLabs** Premium, lifelike voices
57
+ - **OpenAI TTS** Fast, affordable voices
58
+ - **Google Gemini TTS** — Native multilingual support
54
59
 
55
- ### 🔧 Power User Features
60
+ ### 🚀 Developer-First Features
56
61
 
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
62
+ | Feature | Description |
63
+ | ------------------------ | -------------------------------------------------------------------------------- |
64
+ | **`payload.ai` API** | Programmatic access to all AI capabilities in hooks, endpoints, and custom logic |
65
+ | **7 AI Providers** | OpenAI, Anthropic, Google, xAI, ElevenLabs, FAL, OpenAI-Compatible |
66
+ | **Bring Your Own Model** | Add custom models from any provider |
67
+ | **Schema Validation** | Generate structured JSON with Zod or JSON Schema |
68
+ | **Streaming** | Real-time streaming for text and structured output |
69
+ | **Vision Models** | Reference images in prompts for multimodal generation |
63
70
 
64
- ### 🔜 Coming Soon
71
+ ### 🔐 Enterprise Ready
65
72
 
66
- - 📊 Document Analyzer
67
- - Fact Checking
68
- - 🔄 Automated Workflows
69
- - 💡 Editor Suggestions
70
- - 💬 AI Chat Assistant
73
+ - **Encrypted API Keys** — Secure storage in your database
74
+ - **Access Control** — Granular permissions for generation and settings
75
+ - **Custom Base URLs** — Support for proxies and self-hosted models
76
+ - **Multi-Tenant** Custom media upload handlers
71
77
 
72
78
  ---
73
79
 
@@ -77,17 +83,14 @@ This plugin is actively evolving. We're constantly shipping improvements and new
77
83
  pnpm add @ai-stack/payloadcms
78
84
  ```
79
85
 
80
- That's it! Now let's configure it.
81
-
82
86
  ---
83
87
 
84
- ## 🛠️ Quick Setup
88
+ ## 🛠 Quick Start
85
89
 
86
- ### Step 1: Configure the Plugin
87
-
88
- Add to `src/payload.config.ts`:
90
+ ### 1. Add the Plugin
89
91
 
90
92
  ```typescript
93
+ // payload.config.ts
91
94
  import { payloadAiPlugin } from '@ai-stack/payloadcms'
92
95
 
93
96
  export default buildConfig({
@@ -96,18 +99,15 @@ export default buildConfig({
96
99
  collections: {
97
100
  [Posts.slug]: true,
98
101
  },
99
- debugging: false,
100
102
  }),
101
103
  ],
102
- // ... rest of your config
103
104
  })
104
105
  ```
105
106
 
106
- ### Step 2: Enable AI in Your Fields
107
-
108
- Add to your RichText fields (e.g., `src/collections/Posts/index.ts`):
107
+ ### 2. Enable Rich Text AI Features
109
108
 
110
109
  ```typescript
110
+ // collections/Posts.ts
111
111
  import { PayloadAiPluginLexicalEditorFeature } from '@ai-stack/payloadcms'
112
112
 
113
113
  fields: [
@@ -115,254 +115,243 @@ fields: [
115
115
  name: 'content',
116
116
  type: 'richText',
117
117
  editor: lexicalEditor({
118
- features: ({ rootFeatures }) => {
119
- return [
120
- HeadingFeature({ enabledHeadingSizes: ['h1', 'h2', 'h3', 'h4'] }),
121
- // Add this line:
122
- PayloadAiPluginLexicalEditorFeature(),
123
- ]
124
- },
118
+ features: ({ rootFeatures }) => [...rootFeatures, PayloadAiPluginLexicalEditorFeature()],
125
119
  }),
126
120
  },
127
121
  ]
128
122
  ```
129
123
 
130
- ### Step 3: Add Your API Keys
124
+ ### 3. Set Your API Keys
131
125
 
132
- Create a `.env` file in your project root. Add the keys for the providers you want to use:
133
126
  ```env
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
127
+ # .env
128
+ OPENAI_API_KEY=your-openai-api-key
129
+ ANTHROPIC_API_KEY=your-anthropic-api-key # Optional
130
+ GOOGLE_AI_API_KEY=your-google-api-key # Optional
131
+ XAI_API_KEY=your-xai-api-key # Optional
132
+ ELEVENLABS_API_KEY=your-elevenlabs-api-key # Optional
150
133
  ```
151
134
 
152
- **You only need the keys for the providers you plan to use.** Mix and match based on your preferences!
135
+ > **✨ Pro tip:** You can also configure API keys directly in the AI Settings panel within Payload Admin—encrypted and secure.
153
136
 
137
+ ---
154
138
 
155
- **Important:** Restart your server after updating `.env` or plugin settings!
139
+ ## 🚀 Programmatic API (`payload.ai`)
156
140
 
157
- You may also need to regenerate the import map:
158
- ```bash
159
- payload generate:importmap
141
+ Use AI directly in your server-side code—hooks, endpoints, custom scripts, and more.
142
+
143
+ ```typescript
144
+ // Generate text
145
+ const text = await payload.ai.generateText({
146
+ prompt: 'Write a compelling product description',
147
+ provider: 'openai',
148
+ model: 'gpt-4o',
149
+ })
150
+
151
+ // Generate structured data with schema validation
152
+ const product = await payload.ai.generateObject({
153
+ prompt: 'Generate product details for a coffee maker',
154
+ provider: 'anthropic',
155
+ model: 'claude-3-sonnet',
156
+ schema: z.object({
157
+ name: z.string(),
158
+ description: z.string(),
159
+ features: z.array(z.string()),
160
+ price: z.number(),
161
+ }),
162
+ })
163
+
164
+ // Generate images
165
+ const image = await payload.ai.generateMedia({
166
+ prompt: 'A modern minimalist logo for a tech startup',
167
+ provider: 'openai',
168
+ model: 'dall-e-3',
169
+ })
170
+
171
+ // Generate speech
172
+ const audio = await payload.ai.generateMedia({
173
+ prompt: 'Welcome to our store!',
174
+ provider: 'elevenlabs',
175
+ voice: 'Rachel',
176
+ })
177
+
178
+ // Stream responses
179
+ const stream = await payload.ai.streamObject({
180
+ prompt: 'Generate a blog post about AI',
181
+ provider: 'google',
182
+ model: 'gemini-2.5-pro',
183
+ schema: blogPostSchema,
184
+ })
160
185
  ```
161
186
 
162
- ---
187
+ ### Available Methods
163
188
 
164
- ## ⚙️ Advanced Configuration
189
+ | Method | Purpose |
190
+ | ------------------ | -------------------------------------- |
191
+ | `generateText()` | Simple text generation |
192
+ | `generateObject()` | Structured output with Zod/JSON schema |
193
+ | `generateMedia()` | Images, audio (TTS), video |
194
+ | `streamText()` | Streaming text responses |
195
+ | `streamObject()` | Streaming structured output |
196
+ | `getModel()` | Direct access to model instances |
197
+ | `getRegistry()` | Access provider configuration |
165
198
 
166
- <details>
167
- <summary><strong>🔐 Access Control & Multi-Tenant Setup</strong></summary>
199
+ ---
168
200
 
169
- ```typescript
170
- import { payloadAiPlugin } from '@ai-stack/payloadcms'
201
+ ## 🔌 Supported Providers
171
202
 
172
- export default buildConfig({
173
- plugins: [
174
- payloadAiPlugin({
175
- collections: {
176
- [Posts.slug]: true,
177
- },
178
-
179
- // Enable AI for globals too
180
- globals: {
181
- [Home.slug]: true,
182
- },
203
+ | Provider | Text | Image | TTS | Vision |
204
+ | ---------------------- | :--: | :---: | :-: | :----: |
205
+ | **OpenAI** | ✅ | ✅ | ✅ | ✅ |
206
+ | **Anthropic** (Claude) | ✅ | — | — | ✅ |
207
+ | **Google** (Gemini) | ✅ | ✅ | ✅ | ✅ |
208
+ | **xAI** (Grok) | ✅ | — | — | ✅ |
209
+ | **ElevenLabs** | — | — | ✅ | — |
210
+ | **FAL** | — | ✅ | — | — |
211
+ | **OpenAI-Compatible** | ✅ | ✅ | — | — |
183
212
 
184
- // Development helpers
185
- debugging: false,
186
- disableSponsorMessage: false,
187
- generatePromptOnInit: process.env.NODE_ENV !== 'production',
213
+ ### Popular Models
188
214
 
189
- // Specify media collection for GPT-Image-1
190
- uploadCollectionSlug: "media",
215
+ - **Text:** GPT-4o, Claude 3.5 Sonnet, Gemini 2.5 Pro, Grok 4
216
+ - **Image:** DALL-E 3, GPT-Image-1, Imagen 3, Gemini 2.5 Flash
217
+ - **Voice:** ElevenLabs Multilingual v2, OpenAI TTS, Gemini TTS
191
218
 
192
- // Lock down AI features
193
- access: {
194
- generate: ({ req }) => req.user?.role === 'admin',
195
- settings: ({ req }) => req.user?.role === 'admin',
196
- },
219
+ ---
197
220
 
198
- // Customize language options
199
- options: {
200
- enabledLanguages: ["en-US", "zh-SG", "zh-CN", "en"],
201
- },
221
+ ## 📸 Vision Models & Image Input
202
222
 
203
- // Reference additional fields in prompts
204
- promptFields: [
205
- {
206
- name: 'url',
207
- collections: ['images'],
208
- },
209
- {
210
- name: 'markdown',
211
- async getter(doc, {collection}) {
212
- return docToMarkdown(collection, doc)
213
- }
214
- }
215
- ],
216
-
217
- // Control initial prompt generation
218
- seedPrompts: ({path}) => {
219
- if (path.endsWith('.meta.description')) {
220
- return {
221
- data: {
222
- prompt: 'Generate SEO-friendly meta description: {{markdown}}',
223
- }
224
- }
225
- }
226
- if (path.endsWith('.slug')) return false // Disable for slugs
227
- return undefined // Use defaults
228
- },
223
+ Reference images directly in your prompts using the `@fieldName` syntax:
229
224
 
230
- // Custom media upload (useful for multi-tenant)
231
- mediaUpload: async (result, { request, collection }) => {
232
- return request.payload.create({
233
- collection,
234
- data: result.data,
235
- file: result.file,
236
- })
237
- },
238
- }),
239
- ],
240
- })
225
+ ```typescript
226
+ // In your prompt field
227
+ "Describe what's in this image: @heroImage"
228
+
229
+ // Reference specific file from hasMany upload
230
+ 'Analyze this photo: @gallery:product-shot.jpg'
241
231
  ```
242
232
 
243
- </details>
233
+ Images are automatically fetched and sent to vision-capable models like GPT-4o, Claude, Gemini, and Grok Vision.
234
+
235
+ ---
236
+
237
+ ## ⚙️ Advanced Configuration
244
238
 
245
239
  <details>
246
- <summary><strong>🎨 Custom Components & Fields</strong></summary>
240
+ <summary>🔧 Access Control, Multi-Tenant, Custom Prompts</summary>
247
241
 
248
- Custom fields don't automatically inherit AI capabilities. If your AI-enabled fields don't show Compose settings, manually add this component path:
242
+ ```typescript
243
+ payloadAiPlugin({
244
+ collections: {
245
+ [Posts.slug]: true,
246
+ },
247
+ globals: {
248
+ [Home.slug]: true,
249
+ },
249
250
 
250
- ```
251
- @ai-stack/payloadcms/fields#ComposeField
252
- ```
251
+ // Access control
252
+ access: {
253
+ generate: ({ req }) => req.user?.role === 'admin',
254
+ settings: ({ req }) => req.user?.role === 'admin',
255
+ },
253
256
 
254
- **Debug Tip:** Enable `debugging: true` in your plugin config to see which fields have AI enabled.
257
+ // Custom media upload (multi-tenant)
258
+ mediaUpload: async (result, { request, collection }) => {
259
+ return request.payload.create({
260
+ collection,
261
+ data: { ...result.data, tenant: request.user.tenant },
262
+ file: result.file,
263
+ })
264
+ },
255
265
 
256
- </details>
266
+ // Custom prompt seeding
267
+ seedPrompts: ({ path, fieldLabel }) => {
268
+ if (path.endsWith('.meta.description')) {
269
+ return {
270
+ data: {
271
+ prompt: `Generate an SEO-optimized description for: {{title}}`,
272
+ },
273
+ }
274
+ }
275
+ if (path.endsWith('.slug')) return false // Disable AI for slugs
276
+ },
257
277
 
258
- ---
278
+ // Language options for translation
279
+ options: {
280
+ enabledLanguages: ['en-US', 'es', 'fr', 'de', 'zh-CN', 'ja'],
281
+ },
259
282
 
260
- ## 📚 Documentation
283
+ // Expose custom fields in prompts
284
+ promptFields: [
285
+ { name: 'url', collections: ['media'] },
286
+ {
287
+ name: 'summary',
288
+ getter: async (doc) => generateSummary(doc),
289
+ },
290
+ ],
291
+ })
292
+ ```
261
293
 
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
294
+ </details>
267
295
 
268
296
  ---
269
297
 
270
- ## 🤝 Support This Project
298
+ ## 💪 Support This Project
271
299
 
272
- Built with ❤️ in my free time. If this plugin saves you hours of work, consider fueling future development!
300
+ This plugin is built and maintained as an independent project. If it's helped you ship faster or saved you development time, consider supporting its continued development:
273
301
 
274
302
  <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" />
303
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50">
276
304
  </a>
277
305
 
278
- Every coffee keeps the AI models running and new features shipping. Thank you! 🙏
306
+ - **Star the repo** It helps others discover the project
307
+ - 🐛 **Report issues** — Help improve stability
308
+ - 💡 **Share feedback** — Your ideas shape the roadmap
279
309
 
280
310
  ---
281
311
 
282
312
  ## 👥 Contributing
283
313
 
284
- We love contributors! Whether you're fixing typos, suggesting features, or building new capabilities, all contributions are welcome.
314
+ We welcome contributions of all sizes! Whether it's fixing a typo, adding a feature, or improving docs—every bit helps.
285
315
 
286
- ### Ways to Contribute
316
+ Join the conversation on Payload's [Discord](https://discord.com/channels/967097582721572934/1264949995656843345) and let's build something amazing together! 🚀
287
317
 
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!
294
-
295
- ### Local Development
318
+ <details>
319
+ <summary>🔧 Local Development Setup</summary>
296
320
 
297
- Want to hack on the plugin? Here's how:
321
+ This repo includes a minimal Payload app under [dev](dev/README.md) for quick iteration.
298
322
 
299
- #### Prerequisites
323
+ **Prerequisites:**
300
324
 
301
- - Node.js (version in `.nvmrc`)
302
- - pnpm
303
- - Database connection (Postgres or MongoDB)
325
+ - Node.js (see `.nvmrc`) and pnpm
326
+ - Database connection string (`DATABASE_URI`)
304
327
  - Optional: AI provider API keys
305
328
 
306
- #### Setup
307
-
308
329
  ```bash
309
330
  # 1. Install dependencies
310
331
  pnpm install
311
332
 
312
- # 2. Set up environment
333
+ # 2. Setup environment
313
334
  cp dev/.env.example dev/.env
314
- # Edit dev/.env with your DATABASE_URI, PAYLOAD_SECRET, and API keys
335
+ # Edit dev/.env with your DATABASE_URI and PAYLOAD_SECRET
315
336
 
316
337
  # 3. Start development server
317
338
  pnpm dev
318
- # Admin UI available at http://localhost:3000
319
-
320
- # 4. Generate types/importmap if needed
321
- pnpm generate:importmap
322
- pnpm generate:types
323
- ```
324
339
 
325
- #### Development Workflow
326
-
327
- - Plugin source: `src/`
328
- - Test app: `dev/`
329
- - Edit files in `src/` and refresh to see changes
330
-
331
- #### Testing & Quality
332
-
333
- ```bash
334
- pnpm test # Run all tests
335
- pnpm lint # ESLint
336
- pnpm prettier --write . # Format code
340
+ # 4. Other commands
341
+ pnpm test # Run tests
342
+ pnpm lint # Lint code
337
343
  pnpm build # Build plugin
344
+ pnpm generate:importmap # Regenerate import map
345
+ pnpm generate:types # Regenerate Payload types
338
346
  ```
339
347
 
340
- #### Test in Another Project
348
+ **Project Structure:**
341
349
 
342
- ```bash
343
- pnpm pack
344
- # In your other project:
345
- pnpm add /path/to/ai-plugin-*.tgz
346
- ```
347
-
348
- #### Project Structure
350
+ - `src/` — Plugin source code
351
+ - `dev/` — Development Payload app
352
+ - `dev/int.spec.ts` Integration tests
353
+ - `dev/e2e.spec.ts` — End-to-end tests
349
354
 
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
- ```
355
+ </details>
357
356
 
358
357
  ---
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>
@@ -0,0 +1,4 @@
1
+ import type { PayloadRequest } from 'payload';
2
+ import type { PluginConfig } from '../types.js';
3
+ export declare const requireAuthentication: (req: PayloadRequest) => boolean;
4
+ export declare const checkAccess: (req: PayloadRequest, pluginConfig: PluginConfig) => Promise<boolean>;
@@ -0,0 +1,20 @@
1
+ export const requireAuthentication = (req)=>{
2
+ if (!req.user) {
3
+ throw new Error('Authentication required. Please log in to use AI features.');
4
+ }
5
+ return true;
6
+ };
7
+ export const checkAccess = async (req, pluginConfig)=>{
8
+ requireAuthentication(req);
9
+ if (pluginConfig.access?.generate) {
10
+ const hasAccess = await pluginConfig.access.generate({
11
+ req
12
+ });
13
+ if (!hasAccess) {
14
+ throw new Error('Insufficient permissions to use AI generation features.');
15
+ }
16
+ }
17
+ return true;
18
+ };
19
+
20
+ //# sourceMappingURL=checkAccess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/access/checkAccess.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport type { PluginConfig } from '../types.js'\n\nexport const requireAuthentication = (req: PayloadRequest) => {\n if (!req.user) {\n throw new Error('Authentication required. Please log in to use AI features.')\n }\n return true\n}\n\nexport const checkAccess = async (req: PayloadRequest, pluginConfig: PluginConfig) => {\n requireAuthentication(req)\n\n if (pluginConfig.access?.generate) {\n const hasAccess = await pluginConfig.access.generate({ req })\n if (!hasAccess) {\n throw new Error('Insufficient permissions to use AI generation features.')\n }\n }\n\n return true\n}"],"names":["requireAuthentication","req","user","Error","checkAccess","pluginConfig","access","generate","hasAccess"],"mappings":"AAIA,OAAO,MAAMA,wBAAwB,CAACC;IACpC,IAAI,CAACA,IAAIC,IAAI,EAAE;QACb,MAAM,IAAIC,MAAM;IAClB;IACA,OAAO;AACT,EAAC;AAED,OAAO,MAAMC,cAAc,OAAOH,KAAqBI;IACrDL,sBAAsBC;IAEtB,IAAII,aAAaC,MAAM,EAAEC,UAAU;QACjC,MAAMC,YAAY,MAAMH,aAAaC,MAAM,CAACC,QAAQ,CAAC;YAAEN;QAAI;QAC3D,IAAI,CAACO,WAAW;YACd,MAAM,IAAIL,MAAM;QAClB;IACF;IAEA,OAAO;AACT,EAAC"}
@@ -0,0 +1,7 @@
1
+ import type { PayloadGenerateObjectArgs } from './types.js';
2
+ /**
3
+ * Generate structured output using AI SDK's generateObject
4
+ * This is a thin wrapper that resolves the model from the registry
5
+ * and passes everything directly to the AI SDK
6
+ */
7
+ export declare function generateObject(args: PayloadGenerateObjectArgs): Promise<import("ai").GenerateObjectResult<unknown>>;
@@ -0,0 +1,35 @@
1
+ import { jsonSchema, generateObject as sdkGenerateObject } from 'ai';
2
+ import { extractPromptAttachments } from '../../utilities/extractPromptAttachments.js';
3
+ import { getLanguageModel } from '../providers/registry.js';
4
+ function isZodSchema(schema) {
5
+ return typeof schema === 'object' && schema !== null && '_def' in schema;
6
+ }
7
+ /**
8
+ * Generate structured output using AI SDK's generateObject
9
+ * This is a thin wrapper that resolves the model from the registry
10
+ * and passes everything directly to the AI SDK
11
+ */ export async function generateObject(args) {
12
+ const { maxTokens, mode, model: modelId, payload, prompt, provider, providerOptions, schema, system, temperature, ...rest } = args;
13
+ // Extract attachments if needed (from existing utility)
14
+ const processedPrompt = rest.extractAttachments ? extractPromptAttachments(prompt) : prompt;
15
+ // Resolve model from registry
16
+ const model = await getLanguageModel(payload, provider, modelId, providerOptions);
17
+ // Pass directly to AI SDK with minimal transformation
18
+ const options = {
19
+ mode: mode || 'auto',
20
+ model,
21
+ prompt: processedPrompt,
22
+ schema: schema ? isZodSchema(schema) ? schema : jsonSchema(schema) : undefined,
23
+ system,
24
+ temperature: temperature ?? 0.7,
25
+ ...maxTokens ? {
26
+ maxOutputTokens: maxTokens
27
+ } : {}
28
+ };
29
+ if (providerOptions) {
30
+ options.providerOptions = providerOptions;
31
+ }
32
+ return sdkGenerateObject(options);
33
+ }
34
+
35
+ //# sourceMappingURL=generateObject.js.map