@ai-stack/payloadcms 3.2.24-beta → 3.68.0

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 +19 -21
  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
@@ -0,0 +1,207 @@
1
+ 'use client';
2
+ import { SelectInput, useField, useFormFields } from '@payloadcms/ui';
3
+ import React, { useEffect, useMemo, useState } from 'react';
4
+ import { allProviderBlocks } from '../../ai/providers/blocks/index.js';
5
+ /**
6
+ * Find a field by name within a block's fields, searching through tabs
7
+ */
8
+ function findFieldInBlock(block, fieldName) {
9
+ const searchFields = (fields) => {
10
+ for (const field of fields) {
11
+ if ('name' in field && field.name === fieldName) {
12
+ return field;
13
+ }
14
+ if (field.type === 'tabs' && 'tabs' in field) {
15
+ for (const tab of field.tabs) {
16
+ const found = searchFields(tab.fields);
17
+ if (found) {
18
+ return found;
19
+ }
20
+ }
21
+ }
22
+ if (field.type === 'group' && 'fields' in field) {
23
+ const found = searchFields(field.fields);
24
+ if (found) {
25
+ return found;
26
+ }
27
+ }
28
+ }
29
+ return undefined;
30
+ };
31
+ return searchFields(block.fields);
32
+ }
33
+ /**
34
+ * Infer use case from field path
35
+ * Handles both:
36
+ * - AISettings paths: 'defaults.text.model', 'defaults.image.model'
37
+ * - Instructions paths: 'text-settings.model', 'image-settings.model'
38
+ */
39
+ function inferUseCase(path) {
40
+ const pathParts = path.split('.');
41
+ const parentName = pathParts[pathParts.length - 2];
42
+ // AISettings: 'defaults.text.model' -> parentName is 'text'
43
+ // Direct use case names
44
+ if (['image', 'text', 'tts', 'video'].includes(parentName)) {
45
+ return parentName;
46
+ }
47
+ // Instructions: 'text-settings.model' -> parentName is 'text-settings'
48
+ if (parentName === 'image-settings') {
49
+ return 'image';
50
+ }
51
+ if (parentName === 'tts-settings') {
52
+ return 'tts';
53
+ }
54
+ if (parentName === 'text-settings' || parentName === 'richtext-settings') {
55
+ return 'text';
56
+ }
57
+ if (parentName === 'video-settings') {
58
+ return 'video';
59
+ }
60
+ // Default to text
61
+ return 'text';
62
+ }
63
+ export const DynamicModelSelect = (props) => {
64
+ const { name, path } = props;
65
+ // Getting the 'provider' sibling field value
66
+ const parentPath = path.split('.').slice(0, -1).join('.');
67
+ const providerPath = `${parentPath}.provider`;
68
+ const providerField = useFormFields(([fields]) => fields[providerPath]);
69
+ const providerValue = providerField?.value;
70
+ // Get all form fields to search for live provider configuration (for AISettings context)
71
+ // We filter to only 'providers' fields to avoid unnecessary re-renders,
72
+ // but note that the selector runs on every change.
73
+ const formProviders = useFormFields(([fields]) => {
74
+ const providers = {};
75
+ if (fields && typeof fields === 'object') {
76
+ Object.keys(fields).forEach((key) => {
77
+ if (key.startsWith('providers.')) {
78
+ providers[key] = fields[key];
79
+ }
80
+ });
81
+ }
82
+ return providers;
83
+ });
84
+ const { setValue, value } = useField({ path });
85
+ // State to hold fetched providers data
86
+ const [providersData, setProvidersData] = useState([]);
87
+ // Fetch AI Settings global to get configured providers
88
+ useEffect(() => {
89
+ const fetchSettings = async () => {
90
+ try {
91
+ const response = await fetch('/api/globals/ai-settings?depth=1');
92
+ if (response.ok) {
93
+ const data = await response.json();
94
+ if (data && data.providers) {
95
+ setProvidersData(data.providers);
96
+ }
97
+ }
98
+ }
99
+ catch (error) {
100
+ console.error('Error fetching AI settings:', error);
101
+ }
102
+ };
103
+ fetchSettings().catch(console.error);
104
+ }, []);
105
+ const inferredUseCase = useMemo(() => inferUseCase(path), [path]);
106
+ const options = useMemo(() => {
107
+ if (!providerValue) {
108
+ return [];
109
+ }
110
+ const optionsList = [];
111
+ // Strategy:
112
+ // 1. Try to find provider in LIVE form state (if editing AISettings)
113
+ // 2. If not found, try to find in FETCHED API data (if editing Instructions or saved AISettings)
114
+ // 3. Fall back to static defaults from block definitions
115
+ let foundInForm = false;
116
+ let foundInAPI = false;
117
+ // --- 1. Live Form Search ---
118
+ // Iterate through form fields to find the matching provider block
119
+ // We assume standard block structure: providers.0.blockType, etc.
120
+ // We search up to 20 providers to be safe (unlikely to have more)
121
+ for (let i = 0; i < 20; i++) {
122
+ const typeKey = `providers.${i}.blockType`;
123
+ const typeField = formProviders[typeKey];
124
+ if (!typeField) {
125
+ break;
126
+ } // Stop if no more blocks (or gap)
127
+ if (typeof typeField === 'object' && 'value' in typeField && typeField.value === providerValue) {
128
+ foundInForm = true;
129
+ // Found the provider! Now iterate its models
130
+ // Models path: providers.0.models.0.id
131
+ for (let j = 0; j < 50; j++) {
132
+ const idKey = `providers.${i}.models.${j}.id`;
133
+ const nameKey = `providers.${i}.models.${j}.name`;
134
+ const useCaseKey = `providers.${i}.models.${j}.useCase`;
135
+ const enabledKey = `providers.${i}.models.${j}.enabled`;
136
+ const idField = formProviders[idKey];
137
+ if (!idField) {
138
+ break;
139
+ } // Stop if no more models
140
+ const modelId = (idField).value;
141
+ const modelName = (formProviders[nameKey])?.value;
142
+ const modelUseCase = (formProviders[useCaseKey])?.value;
143
+ const modelEnabled = (formProviders[enabledKey])?.value;
144
+ // Check use case and enabled status (default to enabled if undefined)
145
+ if (modelUseCase === inferredUseCase && modelEnabled !== false) {
146
+ optionsList.push({
147
+ label: modelName || modelId,
148
+ value: modelId,
149
+ });
150
+ }
151
+ }
152
+ break; // Stop searching providers
153
+ }
154
+ }
155
+ // --- 2. API Data Search (if not found in form) ---
156
+ if (!foundInForm) {
157
+ const userProviderBlock = providersData.find((p) => p.blockType === providerValue);
158
+ if (userProviderBlock && userProviderBlock.models) {
159
+ foundInAPI = true;
160
+ userProviderBlock.models.forEach((m) => {
161
+ if (m.useCase === inferredUseCase && m.enabled !== false) {
162
+ // Avoid duplicates
163
+ if (!optionsList.some((opt) => opt.value === m.id)) {
164
+ optionsList.push({
165
+ label: m.name,
166
+ value: m.id,
167
+ });
168
+ }
169
+ }
170
+ });
171
+ }
172
+ }
173
+ // --- 3. Static Defaults (if not found in form OR API) ---
174
+ // Note: We only fall back to static if we didn't find ANY configuration for this provider.
175
+ // If we found the provider but it had no models for this use case, we show empty list (correct).
176
+ if (!foundInForm && !foundInAPI) {
177
+ const staticBlock = allProviderBlocks.find((b) => b.slug === providerValue);
178
+ if (staticBlock) {
179
+ // Search through tabs to find models field
180
+ const modelsField = findFieldInBlock(staticBlock, 'models');
181
+ const defaultModels = modelsField && 'defaultValue' in modelsField ? modelsField.defaultValue : [];
182
+ defaultModels.forEach((m) => {
183
+ if (m.useCase === inferredUseCase && m.enabled !== false) {
184
+ optionsList.push({
185
+ label: m.name,
186
+ value: m.id,
187
+ });
188
+ }
189
+ });
190
+ }
191
+ }
192
+ return optionsList;
193
+ }, [providerValue, providersData, inferredUseCase, formProviders]);
194
+ return (<div className="field-type select">
195
+ <label className="field-label" htmlFor={path}>
196
+ Model
197
+ </label>
198
+ <SelectInput name={name} onChange={(option) => {
199
+ if (option && typeof option === 'object' && 'value' in option) {
200
+ setValue(option.value);
201
+ }
202
+ else {
203
+ setValue(option);
204
+ }
205
+ }} options={options} path={path} value={value}/>
206
+ </div>);
207
+ };
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ type Props = {
3
+ name: string;
4
+ path: string;
5
+ };
6
+ export declare const DynamicProviderSelect: React.FC<Props>;
7
+ export {};
@@ -0,0 +1,101 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { SelectInput, useField } from '@payloadcms/ui';
4
+ import React, { useEffect, useMemo, useState } from 'react';
5
+ import { allProviderBlocks } from '../../ai/providers/blocks/index.js';
6
+ export const DynamicProviderSelect = (props)=>{
7
+ const { name, path } = props;
8
+ const { setValue, value } = useField({
9
+ path
10
+ });
11
+ // State to hold fetched providers data
12
+ const [providersData, setProvidersData] = useState([]);
13
+ // Fetch AI Settings global to get configured providers
14
+ useEffect(()=>{
15
+ const fetchSettings = async ()=>{
16
+ try {
17
+ const response = await fetch('/api/globals/ai-settings?depth=1');
18
+ if (response.ok) {
19
+ const data = await response.json();
20
+ if (data && data.providers) {
21
+ setProvidersData(data.providers);
22
+ }
23
+ }
24
+ } catch (error) {
25
+ console.error('Error fetching AI settings:', error);
26
+ }
27
+ };
28
+ void fetchSettings();
29
+ }, []);
30
+ const options = useMemo(()=>{
31
+ const optionsList = [];
32
+ const processedProviders = new Set();
33
+ // Iterate through fetched providers to find custom names
34
+ providersData.forEach((provider)=>{
35
+ if (!provider.enabled) {
36
+ return;
37
+ }
38
+ const blockType = provider.blockType;
39
+ const customName = provider.providerName;
40
+ // Get static label as fallback
41
+ const staticBlock = allProviderBlocks.find((b)=>b.slug === blockType);
42
+ const staticLabel = staticBlock?.labels?.singular ? typeof staticBlock.labels.singular === 'string' ? staticBlock.labels.singular : blockType : blockType;
43
+ const label = customName || staticLabel;
44
+ if (!processedProviders.has(blockType)) {
45
+ optionsList.push({
46
+ label,
47
+ value: blockType
48
+ });
49
+ processedProviders.add(blockType);
50
+ } else if (customName) {
51
+ // Update existing label if custom name is available
52
+ const existingOpt = optionsList.find((o)=>o.value === blockType);
53
+ if (existingOpt && existingOpt.label === staticLabel) {
54
+ existingOpt.label = customName;
55
+ }
56
+ }
57
+ });
58
+ // Add any other available providers from blocks that might not be configured yet?
59
+ // Usually we only want to show configured providers in the selection list.
60
+ // But for standard providers (OpenAI, Google), they might not need much config other than API key.
61
+ // If they are not in the list, user can't select them.
62
+ // However, if they are not enabled in settings, maybe we shouldn't show them?
63
+ // Let's stick to showing all available blocks, but prioritizing configured ones with custom names.
64
+ allProviderBlocks.forEach((block)=>{
65
+ if (!processedProviders.has(block.slug)) {
66
+ optionsList.push({
67
+ label: typeof block.labels?.singular === 'string' ? block.labels.singular : block.slug,
68
+ value: block.slug
69
+ });
70
+ }
71
+ });
72
+ return optionsList;
73
+ }, [
74
+ providersData
75
+ ]);
76
+ return /*#__PURE__*/ _jsxs("div", {
77
+ className: "field-type select",
78
+ children: [
79
+ /*#__PURE__*/ _jsx("label", {
80
+ className: "field-label",
81
+ htmlFor: path,
82
+ children: "Provider"
83
+ }),
84
+ /*#__PURE__*/ _jsx(SelectInput, {
85
+ name: name,
86
+ onChange: (option)=>{
87
+ if (option && typeof option === 'object' && 'value' in option) {
88
+ setValue(option.value);
89
+ } else {
90
+ setValue(option);
91
+ }
92
+ },
93
+ options: options,
94
+ path: path,
95
+ value: value
96
+ })
97
+ ]
98
+ });
99
+ };
100
+
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/ui/DynamicProviderSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\n\ntype Props = {\n name: string\n path: string\n}\n\nexport const DynamicProviderSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n const { setValue, value } = useField<string>({ path })\n\n // State to hold fetched providers data\n const [providersData, setProvidersData] = useState<any[]>([])\n\n // Fetch AI Settings global to get configured providers\n useEffect(() => {\n const fetchSettings = async () => {\n try {\n const response = await fetch('/api/globals/ai-settings?depth=1')\n if (response.ok) {\n const data = await response.json()\n if (data && data.providers) {\n setProvidersData(data.providers)\n }\n }\n } catch (error) {\n console.error('Error fetching AI settings:', error)\n }\n }\n\n void fetchSettings()\n }, [])\n\n const options = useMemo(() => {\n const optionsList: { label: string; value: string }[] = []\n const processedProviders = new Set<string>()\n\n // Iterate through fetched providers to find custom names\n providersData.forEach((provider: any) => {\n if (!provider.enabled) {\n return\n }\n\n const blockType = provider.blockType\n const customName = provider.providerName\n\n // Get static label as fallback\n const staticBlock = allProviderBlocks.find((b) => b.slug === blockType)\n const staticLabel = staticBlock?.labels?.singular\n ? typeof staticBlock.labels.singular === 'string'\n ? staticBlock.labels.singular\n : blockType\n : blockType\n\n const label = customName || staticLabel\n\n if (!processedProviders.has(blockType)) {\n optionsList.push({\n label,\n value: blockType,\n })\n processedProviders.add(blockType)\n } else if (customName) {\n // Update existing label if custom name is available\n const existingOpt = optionsList.find((o) => o.value === blockType)\n if (existingOpt && existingOpt.label === staticLabel) {\n existingOpt.label = customName\n }\n }\n })\n\n // Add any other available providers from blocks that might not be configured yet?\n // Usually we only want to show configured providers in the selection list.\n // But for standard providers (OpenAI, Google), they might not need much config other than API key.\n // If they are not in the list, user can't select them.\n // However, if they are not enabled in settings, maybe we shouldn't show them?\n // Let's stick to showing all available blocks, but prioritizing configured ones with custom names.\n\n allProviderBlocks.forEach((block) => {\n if (!processedProviders.has(block.slug)) {\n optionsList.push({\n label: typeof block.labels?.singular === 'string' ? block.labels.singular : block.slug,\n value: block.slug,\n })\n }\n })\n\n return optionsList\n }, [providersData])\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Provider\n </label>\n <SelectInput\n name={name}\n onChange={(option) => {\n if (option && typeof option === 'object' && 'value' in option) {\n setValue(option.value)\n } else {\n setValue(option)\n }\n }}\n options={options as any}\n path={path}\n value={value}\n />\n </div>\n )\n}\n"],"names":["SelectInput","useField","React","useEffect","useMemo","useState","allProviderBlocks","DynamicProviderSelect","props","name","path","setValue","value","providersData","setProvidersData","fetchSettings","response","fetch","ok","data","json","providers","error","console","options","optionsList","processedProviders","Set","forEach","provider","enabled","blockType","customName","providerName","staticBlock","find","b","slug","staticLabel","labels","singular","label","has","push","add","existingOpt","o","block","div","className","htmlFor","onChange","option"],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ 'use client';
2
+ import { SelectInput, useField } from '@payloadcms/ui';
3
+ import React, { useEffect, useMemo, useState } from 'react';
4
+ import { allProviderBlocks } from '../../ai/providers/blocks/index.js';
5
+ export const DynamicProviderSelect = (props) => {
6
+ const { name, path } = props;
7
+ const { setValue, value } = useField({ path });
8
+ // State to hold fetched providers data
9
+ const [providersData, setProvidersData] = useState([]);
10
+ // Fetch AI Settings global to get configured providers
11
+ useEffect(() => {
12
+ const fetchSettings = async () => {
13
+ try {
14
+ const response = await fetch('/api/globals/ai-settings?depth=1');
15
+ if (response.ok) {
16
+ const data = await response.json();
17
+ if (data && data.providers) {
18
+ setProvidersData(data.providers);
19
+ }
20
+ }
21
+ }
22
+ catch (error) {
23
+ console.error('Error fetching AI settings:', error);
24
+ }
25
+ };
26
+ void fetchSettings();
27
+ }, []);
28
+ const options = useMemo(() => {
29
+ const optionsList = [];
30
+ const processedProviders = new Set();
31
+ // Iterate through fetched providers to find custom names
32
+ providersData.forEach((provider) => {
33
+ if (!provider.enabled) {
34
+ return;
35
+ }
36
+ const blockType = provider.blockType;
37
+ const customName = provider.providerName;
38
+ // Get static label as fallback
39
+ const staticBlock = allProviderBlocks.find((b) => b.slug === blockType);
40
+ const staticLabel = staticBlock?.labels?.singular
41
+ ? typeof staticBlock.labels.singular === 'string'
42
+ ? staticBlock.labels.singular
43
+ : blockType
44
+ : blockType;
45
+ const label = customName || staticLabel;
46
+ if (!processedProviders.has(blockType)) {
47
+ optionsList.push({
48
+ label,
49
+ value: blockType,
50
+ });
51
+ processedProviders.add(blockType);
52
+ }
53
+ else if (customName) {
54
+ // Update existing label if custom name is available
55
+ const existingOpt = optionsList.find((o) => o.value === blockType);
56
+ if (existingOpt && existingOpt.label === staticLabel) {
57
+ existingOpt.label = customName;
58
+ }
59
+ }
60
+ });
61
+ // Add any other available providers from blocks that might not be configured yet?
62
+ // Usually we only want to show configured providers in the selection list.
63
+ // But for standard providers (OpenAI, Google), they might not need much config other than API key.
64
+ // If they are not in the list, user can't select them.
65
+ // However, if they are not enabled in settings, maybe we shouldn't show them?
66
+ // Let's stick to showing all available blocks, but prioritizing configured ones with custom names.
67
+ allProviderBlocks.forEach((block) => {
68
+ if (!processedProviders.has(block.slug)) {
69
+ optionsList.push({
70
+ label: typeof block.labels?.singular === 'string' ? block.labels.singular : block.slug,
71
+ value: block.slug,
72
+ });
73
+ }
74
+ });
75
+ return optionsList;
76
+ }, [providersData]);
77
+ return (<div className="field-type select">
78
+ <label className="field-label" htmlFor={path}>
79
+ Provider
80
+ </label>
81
+ <SelectInput name={name} onChange={(option) => {
82
+ if (option && typeof option === 'object' && 'value' in option) {
83
+ setValue(option.value);
84
+ }
85
+ else {
86
+ setValue(option);
87
+ }
88
+ }} options={options} path={path} value={value}/>
89
+ </div>);
90
+ };
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ type Props = {
3
+ name: string;
4
+ path: string;
5
+ };
6
+ export declare const DynamicVoiceSelect: React.FC<Props>;
7
+ export {};
@@ -0,0 +1,104 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { SelectInput, useField, useFormFields } from '@payloadcms/ui';
4
+ import React, { useEffect, useMemo, useState } from 'react';
5
+ export const DynamicVoiceSelect = (props)=>{
6
+ const { name, path } = props;
7
+ // Get provider from siblings
8
+ const parentPath = path.split('.').slice(0, -1).join('.');
9
+ // Accessing provider from sibling data in a group
10
+ const providerField = useFormFields(([fields])=>fields[`${parentPath}.provider`]);
11
+ const provider = providerField?.value;
12
+ const { setValue, value } = useField({
13
+ path
14
+ });
15
+ const [aiSettings, setAiSettings] = useState(null);
16
+ useEffect(()=>{
17
+ fetch('/api/globals/ai-settings?depth=1').then((res)=>res.json()).then((data)=>setAiSettings(data)).catch((err)=>console.error('Error fetching AI settings:', err));
18
+ }, []);
19
+ const voices = useMemo(()=>{
20
+ if (!provider || !aiSettings) {
21
+ return [];
22
+ }
23
+ const providerBlock = aiSettings.providers?.find((p)=>p.blockType === provider && p.enabled);
24
+ if (!providerBlock) {
25
+ return [];
26
+ }
27
+ // Get voices from provider block
28
+ const voicesArray = providerBlock.voices || [];
29
+ return voicesArray.filter((v)=>v.enabled !== false).map((v)=>({
30
+ label: v.name || v.id,
31
+ value: v.id
32
+ }));
33
+ }, [
34
+ provider,
35
+ aiSettings
36
+ ]);
37
+ if (!provider) {
38
+ return /*#__PURE__*/ _jsxs("div", {
39
+ className: "field-type text",
40
+ children: [
41
+ /*#__PURE__*/ _jsx("label", {
42
+ className: "field-label",
43
+ htmlFor: path,
44
+ children: "Voice"
45
+ }),
46
+ /*#__PURE__*/ _jsx("p", {
47
+ style: {
48
+ color: 'var(--theme-elevation-600)',
49
+ fontSize: '13px'
50
+ },
51
+ children: "Please select a provider first."
52
+ })
53
+ ]
54
+ });
55
+ }
56
+ if (voices.length === 0) {
57
+ return /*#__PURE__*/ _jsxs("div", {
58
+ className: "field-type text",
59
+ children: [
60
+ /*#__PURE__*/ _jsx("label", {
61
+ className: "field-label",
62
+ htmlFor: path,
63
+ children: "Voice"
64
+ }),
65
+ /*#__PURE__*/ _jsxs("p", {
66
+ style: {
67
+ color: 'var(--theme-elevation-600)',
68
+ fontSize: '13px'
69
+ },
70
+ children: [
71
+ "No voices available. Please configure voices in AI Settings for ",
72
+ provider,
73
+ "."
74
+ ]
75
+ })
76
+ ]
77
+ });
78
+ }
79
+ return /*#__PURE__*/ _jsxs("div", {
80
+ className: "field-type select",
81
+ children: [
82
+ /*#__PURE__*/ _jsx("label", {
83
+ className: "field-label",
84
+ htmlFor: path,
85
+ children: "Voice"
86
+ }),
87
+ /*#__PURE__*/ _jsx(SelectInput, {
88
+ name: name,
89
+ onChange: (option)=>{
90
+ if (option && typeof option === 'object' && 'value' in option) {
91
+ setValue(option.value);
92
+ } else {
93
+ setValue(option);
94
+ }
95
+ },
96
+ options: voices,
97
+ path: path,
98
+ value: value
99
+ })
100
+ ]
101
+ });
102
+ };
103
+
104
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/ui/DynamicVoiceSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\ntype Props = {\n name: string\n path: string\n}\n\nexport const DynamicVoiceSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n // Get provider from siblings\n const parentPath = path.split('.').slice(0, -1).join('.')\n // Accessing provider from sibling data in a group\n const providerField = useFormFields(([fields]) => fields[`${parentPath}.provider`])\n const provider = providerField?.value as string\n\n const { setValue, value } = useField<string>({ path })\n const [aiSettings, setAiSettings] = useState<any>(null)\n\n useEffect(() => {\n fetch('/api/globals/ai-settings?depth=1')\n .then((res) => res.json())\n .then((data) => setAiSettings(data))\n .catch((err) => console.error('Error fetching AI settings:', err))\n }, [])\n\n const voices = useMemo(() => {\n if (!provider || !aiSettings) {\n return []\n }\n\n const providerBlock = aiSettings.providers?.find(\n (p: any) => p.blockType === provider && p.enabled,\n )\n if (!providerBlock) {\n return []\n }\n\n // Get voices from provider block\n const voicesArray = providerBlock.voices || []\n\n return voicesArray\n .filter((v: any) => v.enabled !== false)\n .map((v: any) => ({\n label: v.name || v.id,\n value: v.id,\n }))\n }, [provider, aiSettings])\n\n if (!provider) {\n return (\n <div className=\"field-type text\">\n <label className=\"field-label\" htmlFor={path}>\n Voice\n </label>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px' }}>\n Please select a provider first.\n </p>\n </div>\n )\n }\n\n if (voices.length === 0) {\n return (\n <div className=\"field-type text\">\n <label className=\"field-label\" htmlFor={path}>\n Voice\n </label>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px' }}>\n No voices available. Please configure voices in AI Settings for {provider}.\n </p>\n </div>\n )\n }\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Voice\n </label>\n <SelectInput\n name={name}\n onChange={(option) => {\n if (option && typeof option === 'object' && 'value' in option) {\n setValue(option.value as string)\n } else {\n setValue(option)\n }\n }}\n options={voices}\n path={path}\n value={value}\n />\n </div>\n )\n}\n"],"names":["SelectInput","useField","useFormFields","React","useEffect","useMemo","useState","DynamicVoiceSelect","props","name","path","parentPath","split","slice","join","providerField","fields","provider","value","setValue","aiSettings","setAiSettings","fetch","then","res","json","data","catch","err","console","error","voices","providerBlock","providers","find","p","blockType","enabled","voicesArray","filter","v","map","label","id","div","className","htmlFor","style","color","fontSize","length","onChange","option","options"],"mappings":"AAAA;;AAEA,SAASA,WAAW,EAAEC,QAAQ,EAAEC,aAAa,QAAQ,iBAAgB;AACrE,OAAOC,SAASC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAO3D,OAAO,MAAMC,qBAAsC,CAACC;IAClD,MAAM,EAAEC,IAAI,EAAEC,IAAI,EAAE,GAAGF;IAEvB,6BAA6B;IAC7B,MAAMG,aAAaD,KAAKE,KAAK,CAAC,KAAKC,KAAK,CAAC,GAAG,CAAC,GAAGC,IAAI,CAAC;IACrD,kDAAkD;IAClD,MAAMC,gBAAgBb,cAAc,CAAC,CAACc,OAAO,GAAKA,MAAM,CAAC,CAAC,EAAEL,WAAW,SAAS,CAAC,CAAC;IAClF,MAAMM,WAAWF,eAAeG;IAEhC,MAAM,EAAEC,QAAQ,EAAED,KAAK,EAAE,GAAGjB,SAAiB;QAAES;IAAK;IACpD,MAAM,CAACU,YAAYC,cAAc,GAAGf,SAAc;IAElDF,UAAU;QACRkB,MAAM,oCACHC,IAAI,CAAC,CAACC,MAAQA,IAAIC,IAAI,IACtBF,IAAI,CAAC,CAACG,OAASL,cAAcK,OAC7BC,KAAK,CAAC,CAACC,MAAQC,QAAQC,KAAK,CAAC,+BAA+BF;IACjE,GAAG,EAAE;IAEL,MAAMG,SAAS1B,QAAQ;QACrB,IAAI,CAACY,YAAY,CAACG,YAAY;YAC5B,OAAO,EAAE;QACX;QAEA,MAAMY,gBAAgBZ,WAAWa,SAAS,EAAEC,KAC1C,CAACC,IAAWA,EAAEC,SAAS,KAAKnB,YAAYkB,EAAEE,OAAO;QAEnD,IAAI,CAACL,eAAe;YAClB,OAAO,EAAE;QACX;QAEA,iCAAiC;QACjC,MAAMM,cAAcN,cAAcD,MAAM,IAAI,EAAE;QAE9C,OAAOO,YACJC,MAAM,CAAC,CAACC,IAAWA,EAAEH,OAAO,KAAK,OACjCI,GAAG,CAAC,CAACD,IAAY,CAAA;gBAChBE,OAAOF,EAAE/B,IAAI,IAAI+B,EAAEG,EAAE;gBACrBzB,OAAOsB,EAAEG,EAAE;YACb,CAAA;IACJ,GAAG;QAAC1B;QAAUG;KAAW;IAEzB,IAAI,CAACH,UAAU;QACb,qBACE,MAAC2B;YAAIC,WAAU;;8BACb,KAACH;oBAAMG,WAAU;oBAAcC,SAASpC;8BAAM;;8BAG9C,KAACyB;oBAAEY,OAAO;wBAAEC,OAAO;wBAA8BC,UAAU;oBAAO;8BAAG;;;;IAK3E;IAEA,IAAIlB,OAAOmB,MAAM,KAAK,GAAG;QACvB,qBACE,MAACN;YAAIC,WAAU;;8BACb,KAACH;oBAAMG,WAAU;oBAAcC,SAASpC;8BAAM;;8BAG9C,MAACyB;oBAAEY,OAAO;wBAAEC,OAAO;wBAA8BC,UAAU;oBAAO;;wBAAG;wBACFhC;wBAAS;;;;;IAIlF;IAEA,qBACE,MAAC2B;QAAIC,WAAU;;0BACb,KAACH;gBAAMG,WAAU;gBAAcC,SAASpC;0BAAM;;0BAG9C,KAACV;gBACCS,MAAMA;gBACN0C,UAAU,CAACC;oBACT,IAAIA,UAAU,OAAOA,WAAW,YAAY,WAAWA,QAAQ;wBAC7DjC,SAASiC,OAAOlC,KAAK;oBACvB,OAAO;wBACLC,SAASiC;oBACX;gBACF;gBACAC,SAAStB;gBACTrB,MAAMA;gBACNQ,OAAOA;;;;AAIf,EAAC"}
@@ -0,0 +1,69 @@
1
+ 'use client';
2
+ import { SelectInput, useField, useFormFields } from '@payloadcms/ui';
3
+ import React, { useEffect, useMemo, useState } from 'react';
4
+ export const DynamicVoiceSelect = (props) => {
5
+ const { name, path } = props;
6
+ // Get provider from siblings
7
+ const parentPath = path.split('.').slice(0, -1).join('.');
8
+ // Accessing provider from sibling data in a group
9
+ const providerField = useFormFields(([fields]) => fields[`${parentPath}.provider`]);
10
+ const provider = providerField?.value;
11
+ const { setValue, value } = useField({ path });
12
+ const [aiSettings, setAiSettings] = useState(null);
13
+ useEffect(() => {
14
+ fetch('/api/globals/ai-settings?depth=1')
15
+ .then((res) => res.json())
16
+ .then((data) => setAiSettings(data))
17
+ .catch((err) => console.error('Error fetching AI settings:', err));
18
+ }, []);
19
+ const voices = useMemo(() => {
20
+ if (!provider || !aiSettings) {
21
+ return [];
22
+ }
23
+ const providerBlock = aiSettings.providers?.find((p) => p.blockType === provider && p.enabled);
24
+ if (!providerBlock) {
25
+ return [];
26
+ }
27
+ // Get voices from provider block
28
+ const voicesArray = providerBlock.voices || [];
29
+ return voicesArray
30
+ .filter((v) => v.enabled !== false)
31
+ .map((v) => ({
32
+ label: v.name || v.id,
33
+ value: v.id,
34
+ }));
35
+ }, [provider, aiSettings]);
36
+ if (!provider) {
37
+ return (<div className="field-type text">
38
+ <label className="field-label" htmlFor={path}>
39
+ Voice
40
+ </label>
41
+ <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px' }}>
42
+ Please select a provider first.
43
+ </p>
44
+ </div>);
45
+ }
46
+ if (voices.length === 0) {
47
+ return (<div className="field-type text">
48
+ <label className="field-label" htmlFor={path}>
49
+ Voice
50
+ </label>
51
+ <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px' }}>
52
+ No voices available. Please configure voices in AI Settings for {provider}.
53
+ </p>
54
+ </div>);
55
+ }
56
+ return (<div className="field-type select">
57
+ <label className="field-label" htmlFor={path}>
58
+ Voice
59
+ </label>
60
+ <SelectInput name={name} onChange={(option) => {
61
+ if (option && typeof option === 'object' && 'value' in option) {
62
+ setValue(option.value);
63
+ }
64
+ else {
65
+ setValue(option);
66
+ }
67
+ }} options={voices} path={path} value={value}/>
68
+ </div>);
69
+ };
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ type Props = {
3
+ label?: string;
4
+ path: string;
5
+ required?: boolean;
6
+ };
7
+ export declare const EncryptedTextField: React.FC<Props>;
8
+ export {};