@ai-stack/payloadcms 3.2.20-beta → 3.2.21-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/dist/ai/models/anthropic/index.js +9 -15
- package/dist/ai/models/anthropic/index.js.map +1 -1
- package/dist/ai/models/generateObject.d.ts +11 -0
- package/dist/ai/models/generateObject.js +22 -0
- package/dist/ai/models/generateObject.js.map +1 -0
- package/dist/ai/models/openai/index.js +19 -17
- package/dist/ai/models/openai/index.js.map +1 -1
- package/dist/collections/Instructions.js +2 -0
- package/dist/collections/Instructions.js.map +1 -1
- package/dist/endpoints/index.js +55 -6
- package/dist/endpoints/index.js.map +1 -1
- package/dist/fields/ComposeField/ComposeField.js +5 -3
- package/dist/fields/ComposeField/ComposeField.js.map +1 -1
- package/dist/fields/ComposeField/ComposeField.jsx +32 -0
- package/dist/fields/LexicalEditor/ComposeFeatureComponent.js +1 -1
- package/dist/fields/LexicalEditor/ComposeFeatureComponent.js.map +1 -1
- package/dist/fields/LexicalEditor/ComposeFeatureComponent.jsx +24 -0
- package/dist/fields/LexicalEditor/feature.client.jsx +21 -0
- package/dist/fields/PromptEditorField/PromptEditorField.jsx +42 -0
- package/dist/fields/SelectField/SelectField.jsx +38 -0
- package/dist/providers/FieldProvider/FieldProvider.d.ts +7 -4
- package/dist/providers/FieldProvider/FieldProvider.js +7 -6
- package/dist/providers/FieldProvider/FieldProvider.js.map +1 -1
- package/dist/providers/FieldProvider/FieldProvider.jsx +27 -0
- package/dist/providers/FieldProvider/useFieldProps.d.ts +1 -1
- package/dist/providers/FieldProvider/useFieldProps.js +2 -2
- package/dist/providers/FieldProvider/useFieldProps.js.map +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +45 -0
- package/dist/types.d.ts +4 -4
- package/dist/types.js.map +1 -1
- package/dist/ui/Compose/Compose.js +12 -81
- package/dist/ui/Compose/Compose.js.map +1 -1
- package/dist/ui/Compose/Compose.jsx +141 -0
- package/dist/ui/Compose/UndoRedoActions.jsx +34 -0
- package/dist/ui/Compose/compose.module.css +99 -12
- package/dist/ui/Compose/hooks/menu/Item.jsx +15 -0
- package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +58 -0
- package/dist/ui/Compose/hooks/menu/items.jsx +10 -0
- package/dist/ui/Compose/hooks/menu/useMenu.js +1 -1
- package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/useMenu.jsx +89 -0
- package/dist/ui/Compose/hooks/useActiveFieldTracking.d.ts +5 -0
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js +148 -0
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -0
- package/dist/ui/Compose/hooks/useGenerate.js +46 -79
- package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
- package/dist/ui/Icons/Icons.jsx +78 -0
- package/dist/ui/Icons/LottieAnimation.jsx +64 -0
- package/dist/utilities/extractPromptAttachments.d.ts +2 -2
- package/dist/utilities/extractPromptAttachments.js.map +1 -1
- package/dist/utilities/fieldToJsonSchema.d.ts +37 -0
- package/dist/utilities/fieldToJsonSchema.js +274 -0
- package/dist/utilities/fieldToJsonSchema.js.map +1 -0
- package/dist/utilities/getFieldBySchemaPath.d.ts +12 -1
- package/dist/utilities/getFieldBySchemaPath.js +63 -29
- package/dist/utilities/getFieldBySchemaPath.js.map +1 -1
- package/package.json +2 -1
- package/dist/ai/models/anthropic/generateRichText.d.ts +0 -1
- package/dist/ai/models/anthropic/generateRichText.js +0 -36
- package/dist/ai/models/anthropic/generateRichText.js.map +0 -1
- package/dist/ai/models/openai/generateRichText.d.ts +0 -1
- package/dist/ai/models/openai/generateRichText.js +0 -37
- package/dist/ai/models/openai/generateRichText.js.map +0 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useField } from '@payloadcms/ui';
|
|
3
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import { useFieldProps } from '../../../../providers/FieldProvider/useFieldProps.js';
|
|
5
|
+
import { Compose, Proofread, Rephrase } from './items.js';
|
|
6
|
+
import { menuItemsMap } from './itemsMap.js';
|
|
7
|
+
import styles from './menu.module.scss';
|
|
8
|
+
const getActiveComponent = (ac) => {
|
|
9
|
+
switch (ac) {
|
|
10
|
+
case 'Compose':
|
|
11
|
+
return Compose;
|
|
12
|
+
case 'Proofread':
|
|
13
|
+
return Proofread;
|
|
14
|
+
case 'Rephrase':
|
|
15
|
+
return Rephrase;
|
|
16
|
+
default:
|
|
17
|
+
return Rephrase;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
export const useMenu = (menuEvents, options) => {
|
|
21
|
+
const { field: { type: fieldType } = {}, path: pathFromContext } = useFieldProps();
|
|
22
|
+
const field = useField({ path: pathFromContext ?? '' });
|
|
23
|
+
const [activeComponent, setActiveComponent] = useState('Rephrase');
|
|
24
|
+
const { initialValue, value } = field;
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!value) {
|
|
27
|
+
setActiveComponent('Compose');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (menuItemsMap.some((i) => i.excludedFor?.includes(fieldType ?? ''))) {
|
|
31
|
+
setActiveComponent('Compose');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (typeof value === 'string' && value !== initialValue) {
|
|
35
|
+
setActiveComponent('Proofread');
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
setActiveComponent('Rephrase');
|
|
39
|
+
}
|
|
40
|
+
}, [initialValue, value, fieldType]);
|
|
41
|
+
const MemoizedActiveComponent = useMemo(() => {
|
|
42
|
+
return ({ isLoading, stop }) => {
|
|
43
|
+
const ActiveComponent = getActiveComponent(activeComponent);
|
|
44
|
+
const activeItem = menuItemsMap.find((i) => i.name === activeComponent);
|
|
45
|
+
return (<ActiveComponent hideIcon onClick={(data) => {
|
|
46
|
+
if (!isLoading) {
|
|
47
|
+
const trigger = menuEvents[`on${activeComponent}`];
|
|
48
|
+
if (typeof trigger === 'function') {
|
|
49
|
+
trigger(data);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.error('No trigger found for', activeComponent);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
stop();
|
|
57
|
+
}
|
|
58
|
+
}} title={isLoading ? 'Click to stop' : activeItem.name}>
|
|
59
|
+
{isLoading && activeItem.loadingText}
|
|
60
|
+
</ActiveComponent>);
|
|
61
|
+
};
|
|
62
|
+
}, [activeComponent, menuEvents]);
|
|
63
|
+
const filteredMenuItems = useMemo(() => menuItemsMap.filter((i) => {
|
|
64
|
+
if (i.name === 'Settings' && !options.isConfigAllowed) {
|
|
65
|
+
return false;
|
|
66
|
+
} // Disable settings if a user role is not permitted
|
|
67
|
+
return i.name !== activeComponent && !i.excludedFor?.includes(fieldType ?? '');
|
|
68
|
+
}), [activeComponent, fieldType, options.isConfigAllowed]);
|
|
69
|
+
const MemoizedMenu = useMemo(() => {
|
|
70
|
+
return ({ isLoading, onClose }) => (<div className={styles.menu}>
|
|
71
|
+
{filteredMenuItems.map((i) => {
|
|
72
|
+
const Action = i.component;
|
|
73
|
+
return (<Action disabled={isLoading} key={i.name} onClick={(data) => {
|
|
74
|
+
if (i.name !== 'Settings') {
|
|
75
|
+
setActiveComponent(i.name);
|
|
76
|
+
}
|
|
77
|
+
menuEvents[`on${i.name}`]?.(data);
|
|
78
|
+
onClose();
|
|
79
|
+
}}>
|
|
80
|
+
{isLoading && i.loadingText}
|
|
81
|
+
</Action>);
|
|
82
|
+
})}
|
|
83
|
+
</div>);
|
|
84
|
+
}, [filteredMenuItems, menuEvents]);
|
|
85
|
+
return {
|
|
86
|
+
ActiveComponent: MemoizedActiveComponent,
|
|
87
|
+
Menu: MemoizedMenu,
|
|
88
|
+
};
|
|
89
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
let currentContainer = null;
|
|
4
|
+
/**
|
|
5
|
+
* Safely escape CSS selector values
|
|
6
|
+
*/ const cssEscape = (value)=>{
|
|
7
|
+
if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {
|
|
8
|
+
return CSS.escape(value);
|
|
9
|
+
}
|
|
10
|
+
return value.replace(/([ #;?%&,.+*~':"!^$[\]()=>|/@])/g, '\\$1');
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Find container from React Select dropdown elements
|
|
14
|
+
*/ const findContainerFromReactSelect = (target)=>{
|
|
15
|
+
const listbox = target.closest('[role="listbox"]');
|
|
16
|
+
if (!listbox?.id) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const id = cssEscape(listbox.id);
|
|
20
|
+
const selector = `[aria-controls="${id}"], [aria-owns="${id}"]`;
|
|
21
|
+
const control = document.querySelector(selector);
|
|
22
|
+
return control?.closest('.field-type') ?? null;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the .field-type container for a given event target
|
|
26
|
+
*/ const resolveContainerFromTarget = (target)=>{
|
|
27
|
+
if (!(target instanceof HTMLElement)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
// Check for direct parent first
|
|
31
|
+
const direct = target.closest('.field-type');
|
|
32
|
+
if (direct) {
|
|
33
|
+
return direct;
|
|
34
|
+
}
|
|
35
|
+
// Fall back to React Select logic
|
|
36
|
+
return findContainerFromReactSelect(target);
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Update the active container and toggle CSS class
|
|
40
|
+
*/ const setActiveContainer = (next)=>{
|
|
41
|
+
if (currentContainer === next) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
currentContainer?.classList.remove('ai-plugin-active');
|
|
45
|
+
next?.classList.add('ai-plugin-active');
|
|
46
|
+
currentContainer = next;
|
|
47
|
+
};
|
|
48
|
+
const isInteractiveElement = (element)=>{
|
|
49
|
+
const tagName = element.tagName.toLowerCase();
|
|
50
|
+
const interactiveTags = [
|
|
51
|
+
'input',
|
|
52
|
+
'textarea',
|
|
53
|
+
'select',
|
|
54
|
+
'button'
|
|
55
|
+
];
|
|
56
|
+
if (interactiveTags.includes(tagName)) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
// Check for contenteditable
|
|
60
|
+
if (element.isContentEditable) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
// Check for elements with role="textbox" or role="combobox" (React Select)
|
|
64
|
+
const role = element.getAttribute('role');
|
|
65
|
+
if (role && [
|
|
66
|
+
'combobox',
|
|
67
|
+
'listbox',
|
|
68
|
+
'searchbox',
|
|
69
|
+
'textbox'
|
|
70
|
+
].includes(role)) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Handle focus events - only activate if focus is on an interactive element within .field-type
|
|
77
|
+
*/ const onFocusIn = (e)=>{
|
|
78
|
+
const target = e.target;
|
|
79
|
+
if (!(target instanceof HTMLElement)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Only activate if the focused element is actually interactive
|
|
83
|
+
if (!isInteractiveElement(target)) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const container = resolveContainerFromTarget(target);
|
|
87
|
+
// Only update if we found a new container
|
|
88
|
+
if (container) {
|
|
89
|
+
setActiveContainer(container);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Handle pointer/mouse events - only switch when clicking a different .field-type
|
|
94
|
+
*/ const onPointerDown = (e)=>{
|
|
95
|
+
const target = e.target;
|
|
96
|
+
if (!(target instanceof HTMLElement)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const container = resolveContainerFromTarget(target);
|
|
100
|
+
// Only update if we found a container (keeps last active if clicking elsewhere)
|
|
101
|
+
if (container) {
|
|
102
|
+
setActiveContainer(container);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Handle keyboard navigation (Tab key)
|
|
107
|
+
*/ const onKeyDown = (e)=>{
|
|
108
|
+
if (e.key !== 'Tab') {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
requestAnimationFrame(()=>{
|
|
112
|
+
const container = resolveContainerFromTarget(document.activeElement);
|
|
113
|
+
setActiveContainer(container);
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Initialize document-level listeners to track the active field container.
|
|
118
|
+
* When a container is active, it receives the 'ai-plugin-active' class.
|
|
119
|
+
*/ export const useActiveFieldTracking = ()=>{
|
|
120
|
+
useEffect(()=>{
|
|
121
|
+
if (typeof window === 'undefined') {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const pluginWindow = window;
|
|
125
|
+
// Track number of mounted users of the hook
|
|
126
|
+
pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 0) + 1;
|
|
127
|
+
// Initialize listeners only once
|
|
128
|
+
if (!pluginWindow.__aiComposeTracking) {
|
|
129
|
+
document.addEventListener('focusin', onFocusIn, true);
|
|
130
|
+
document.addEventListener('pointerdown', onPointerDown, true);
|
|
131
|
+
document.addEventListener('keydown', onKeyDown, true);
|
|
132
|
+
pluginWindow.__aiComposeTracking = true;
|
|
133
|
+
}
|
|
134
|
+
return ()=>{
|
|
135
|
+
// Decrement and cleanup when the last user unmounts
|
|
136
|
+
pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 1) - 1;
|
|
137
|
+
if ((pluginWindow.__aiComposeTrackingCount ?? 0) <= 0) {
|
|
138
|
+
document.removeEventListener('focusin', onFocusIn, true);
|
|
139
|
+
document.removeEventListener('pointerdown', onPointerDown, true);
|
|
140
|
+
document.removeEventListener('keydown', onKeyDown, true);
|
|
141
|
+
pluginWindow.__aiComposeTracking = false;
|
|
142
|
+
pluginWindow.__aiComposeTrackingCount = 0;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}, []);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
//# sourceMappingURL=useActiveFieldTracking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/Compose/hooks/useActiveFieldTracking.ts"],"sourcesContent":["'use client'\n\nimport { useEffect } from 'react'\n\nlet currentContainer: HTMLElement | null = null\n\n/**\n * Safely escape CSS selector values\n */\nconst cssEscape = (value: string): string => {\n if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {\n return CSS.escape(value)\n }\n return value.replace(/([ #;?%&,.+*~':\"!^$[\\]()=>|/@])/g, '\\\\$1')\n}\n\n/**\n * Find container from React Select dropdown elements\n */\nconst findContainerFromReactSelect = (target: HTMLElement): HTMLElement | null => {\n const listbox = target.closest<HTMLElement>('[role=\"listbox\"]')\n if (!listbox?.id) {\n return null\n }\n\n const id = cssEscape(listbox.id)\n const selector = `[aria-controls=\"${id}\"], [aria-owns=\"${id}\"]`\n const control = document.querySelector<HTMLElement>(selector)\n\n return control?.closest<HTMLElement>('.field-type') ?? null\n}\n\n/**\n * Resolve the .field-type container for a given event target\n */\nconst resolveContainerFromTarget = (target: EventTarget | null): HTMLElement | null => {\n if (!(target instanceof HTMLElement)) {\n return null\n }\n\n // Check for direct parent first\n const direct = target.closest<HTMLElement>('.field-type')\n if (direct) {\n return direct\n }\n\n // Fall back to React Select logic\n return findContainerFromReactSelect(target)\n}\n\n/**\n * Update the active container and toggle CSS class\n */\nconst setActiveContainer = (next: HTMLElement | null): void => {\n if (currentContainer === next) {\n return\n }\n\n currentContainer?.classList.remove('ai-plugin-active')\n next?.classList.add('ai-plugin-active')\n currentContainer = next\n}\n\nconst isInteractiveElement = (element: HTMLElement): boolean => {\n const tagName = element.tagName.toLowerCase()\n const interactiveTags = ['input', 'textarea', 'select', 'button']\n\n if (interactiveTags.includes(tagName)) {\n return true\n }\n\n // Check for contenteditable\n if (element.isContentEditable) {\n return true\n }\n\n // Check for elements with role=\"textbox\" or role=\"combobox\" (React Select)\n const role = element.getAttribute('role')\n if (role && ['combobox', 'listbox', 'searchbox', 'textbox'].includes(role)) {\n return true\n }\n\n return false\n}\n\n/**\n * Handle focus events - only activate if focus is on an interactive element within .field-type\n */\nconst onFocusIn = (e: FocusEvent): void => {\n const target = e.target\n if (!(target instanceof HTMLElement)) {\n return\n }\n\n // Only activate if the focused element is actually interactive\n if (!isInteractiveElement(target)) {\n return\n }\n\n const container = resolveContainerFromTarget(target)\n // Only update if we found a new container\n if (container) {\n setActiveContainer(container)\n }\n}\n\n/**\n * Handle pointer/mouse events - only switch when clicking a different .field-type\n */\nconst onPointerDown = (e: PointerEvent): void => {\n const target = e.target\n if (!(target instanceof HTMLElement)) {\n return\n }\n\n const container = resolveContainerFromTarget(target)\n\n // Only update if we found a container (keeps last active if clicking elsewhere)\n if (container) {\n setActiveContainer(container)\n }\n}\n\n/**\n * Handle keyboard navigation (Tab key)\n */\nconst onKeyDown = (e: KeyboardEvent): void => {\n if (e.key !== 'Tab') {\n return\n }\n\n requestAnimationFrame(() => {\n const container = resolveContainerFromTarget(document.activeElement)\n setActiveContainer(container)\n })\n}\n\n/**\n * Initialize document-level listeners to track the active field container.\n * When a container is active, it receives the 'ai-plugin-active' class.\n */\nexport const useActiveFieldTracking = (): void => {\n useEffect(() => {\n if (typeof window === 'undefined') {\n return\n }\n\n const pluginWindow = window as {\n __aiComposeTracking?: boolean\n __aiComposeTrackingCount?: number\n } & Window\n\n // Track number of mounted users of the hook\n pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 0) + 1\n\n // Initialize listeners only once\n if (!pluginWindow.__aiComposeTracking) {\n document.addEventListener('focusin', onFocusIn, true)\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown, true)\n pluginWindow.__aiComposeTracking = true\n }\n\n return () => {\n // Decrement and cleanup when the last user unmounts\n pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 1) - 1\n if ((pluginWindow.__aiComposeTrackingCount ?? 0) <= 0) {\n document.removeEventListener('focusin', onFocusIn, true)\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown, true)\n pluginWindow.__aiComposeTracking = false\n pluginWindow.__aiComposeTrackingCount = 0\n }\n }\n }, [])\n}\n"],"names":["useEffect","currentContainer","cssEscape","value","CSS","escape","replace","findContainerFromReactSelect","target","listbox","closest","id","selector","control","document","querySelector","resolveContainerFromTarget","HTMLElement","direct","setActiveContainer","next","classList","remove","add","isInteractiveElement","element","tagName","toLowerCase","interactiveTags","includes","isContentEditable","role","getAttribute","onFocusIn","e","container","onPointerDown","onKeyDown","key","requestAnimationFrame","activeElement","useActiveFieldTracking","window","pluginWindow","__aiComposeTrackingCount","__aiComposeTracking","addEventListener","removeEventListener"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { experimental_useObject as useObject } from '@ai-sdk/react';
|
|
2
2
|
import { useEditorConfigContext } from '@payloadcms/richtext-lexical/client';
|
|
3
3
|
import { toast, useConfig, useDocumentInfo, useField, useForm, useLocale } from '@payloadcms/ui';
|
|
4
4
|
import { jsonSchema } from 'ai';
|
|
@@ -6,6 +6,7 @@ import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
|
6
6
|
import { PLUGIN_API_ENDPOINT_GENERATE, PLUGIN_API_ENDPOINT_GENERATE_UPLOAD, PLUGIN_INSTRUCTIONS_TABLE, PLUGIN_NAME } from '../../../defaults.js';
|
|
7
7
|
import { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js';
|
|
8
8
|
import { editorSchemaValidator } from '../../../utilities/editorSchemaValidator.js';
|
|
9
|
+
import { fieldToJsonSchema } from '../../../utilities/fieldToJsonSchema.js';
|
|
9
10
|
import { setSafeLexicalState } from '../../../utilities/setSafeLexicalState.js';
|
|
10
11
|
import { useHistory } from './useHistory.js';
|
|
11
12
|
export const useGenerate = ({ instructionId })=>{
|
|
@@ -17,7 +18,7 @@ export const useGenerate = ({ instructionId })=>{
|
|
|
17
18
|
}, [
|
|
18
19
|
instructionId
|
|
19
20
|
]);
|
|
20
|
-
const {
|
|
21
|
+
const { field, path: pathFromContext } = useFieldProps();
|
|
21
22
|
const editorConfigContext = useEditorConfigContext();
|
|
22
23
|
const { editor } = editorConfigContext;
|
|
23
24
|
const { config } = useConfig();
|
|
@@ -56,6 +57,24 @@ export const useGenerate = ({ instructionId })=>{
|
|
|
56
57
|
}), [
|
|
57
58
|
memoizedValidator
|
|
58
59
|
]);
|
|
60
|
+
// Active JSON schema for useObject based on field type
|
|
61
|
+
const activeSchema = useMemo(()=>{
|
|
62
|
+
const f = field;
|
|
63
|
+
const fieldType = f?.type;
|
|
64
|
+
if (fieldType === 'richText') {
|
|
65
|
+
return memoizedSchema;
|
|
66
|
+
}
|
|
67
|
+
if (f && f.name && fieldType) {
|
|
68
|
+
const schemaJson = fieldToJsonSchema(f);
|
|
69
|
+
if (schemaJson && Object.keys(schemaJson).length > 0) {
|
|
70
|
+
return jsonSchema(schemaJson);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}, [
|
|
75
|
+
field,
|
|
76
|
+
memoizedSchema
|
|
77
|
+
]);
|
|
59
78
|
const { isLoading: loadingObject, object, stop: objectStop, submit } = useObject({
|
|
60
79
|
api: `/api${PLUGIN_API_ENDPOINT_GENERATE}`,
|
|
61
80
|
onError: (error)=>{
|
|
@@ -63,50 +82,35 @@ export const useGenerate = ({ instructionId })=>{
|
|
|
63
82
|
console.error('Error generating object:', error);
|
|
64
83
|
},
|
|
65
84
|
onFinish: (result)=>{
|
|
66
|
-
if (result.object) {
|
|
67
|
-
|
|
68
|
-
|
|
85
|
+
if (result.object && field) {
|
|
86
|
+
if (field.type === 'richText') {
|
|
87
|
+
setHistory(result.object);
|
|
88
|
+
setValue(result.object);
|
|
89
|
+
} else if ('name' in field) {
|
|
90
|
+
setHistory(result.object[field.name]);
|
|
91
|
+
setValue(result.object[field.name]);
|
|
92
|
+
}
|
|
69
93
|
} else {
|
|
70
|
-
console.log('onFinish: result ', result);
|
|
94
|
+
console.log('onFinish: result, field ', result, field);
|
|
71
95
|
}
|
|
72
96
|
},
|
|
73
|
-
schema:
|
|
97
|
+
schema: activeSchema
|
|
74
98
|
});
|
|
75
99
|
useEffect(()=>{
|
|
76
100
|
if (!object) {
|
|
77
101
|
return;
|
|
78
102
|
}
|
|
79
103
|
requestAnimationFrame(()=>{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
104
|
+
if (field?.type === 'richText') {
|
|
105
|
+
setSafeLexicalState(object, editor);
|
|
106
|
+
} else if (field && 'name' in field && object[field.name]) {
|
|
107
|
+
setValue(object[field.name]);
|
|
108
|
+
}
|
|
85
109
|
});
|
|
86
110
|
}, [
|
|
87
111
|
object,
|
|
88
|
-
editor
|
|
89
|
-
|
|
90
|
-
const { complete, completion, isLoading: loadingCompletion, stop: completionStop } = useCompletion({
|
|
91
|
-
api: `${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE}`,
|
|
92
|
-
onError: (error)=>{
|
|
93
|
-
toast.error(`Failed to generate: ${error.message}`);
|
|
94
|
-
console.error('Error generating text:', error);
|
|
95
|
-
},
|
|
96
|
-
onFinish: (prompt, result)=>{
|
|
97
|
-
setHistory(result);
|
|
98
|
-
},
|
|
99
|
-
streamProtocol: 'data'
|
|
100
|
-
});
|
|
101
|
-
useEffect(()=>{
|
|
102
|
-
if (!completion) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
requestAnimationFrame(()=>{
|
|
106
|
-
setValue(completion);
|
|
107
|
-
});
|
|
108
|
-
}, [
|
|
109
|
-
completion
|
|
112
|
+
editor,
|
|
113
|
+
field
|
|
110
114
|
]);
|
|
111
115
|
const streamObject = useCallback(({ action = 'Compose', params })=>{
|
|
112
116
|
const doc = getData();
|
|
@@ -130,31 +134,6 @@ export const useGenerate = ({ instructionId })=>{
|
|
|
130
134
|
instructionIdRef,
|
|
131
135
|
documentId
|
|
132
136
|
]);
|
|
133
|
-
const streamText = useCallback(async ({ action = 'Compose', params })=>{
|
|
134
|
-
const doc = getData();
|
|
135
|
-
const currentInstructionId = instructionIdRef.current;
|
|
136
|
-
const options = {
|
|
137
|
-
action,
|
|
138
|
-
actionParams: params,
|
|
139
|
-
instructionId: currentInstructionId
|
|
140
|
-
};
|
|
141
|
-
await complete('', {
|
|
142
|
-
body: {
|
|
143
|
-
doc: {
|
|
144
|
-
...doc,
|
|
145
|
-
id: documentId
|
|
146
|
-
},
|
|
147
|
-
locale: localFromContext?.code,
|
|
148
|
-
options
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}, [
|
|
152
|
-
getData,
|
|
153
|
-
localFromContext?.code,
|
|
154
|
-
instructionIdRef,
|
|
155
|
-
complete,
|
|
156
|
-
documentId
|
|
157
|
-
]);
|
|
158
137
|
const generateUpload = useCallback(async ()=>{
|
|
159
138
|
const doc = getData();
|
|
160
139
|
const currentInstructionId = instructionIdRef.current;
|
|
@@ -201,39 +180,27 @@ export const useGenerate = ({ instructionId })=>{
|
|
|
201
180
|
collectionSlug
|
|
202
181
|
]);
|
|
203
182
|
const generate = useCallback(async (options)=>{
|
|
204
|
-
if (type === '
|
|
205
|
-
return streamObject(options ?? {
|
|
206
|
-
action: 'Compose'
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
if ([
|
|
210
|
-
'text',
|
|
211
|
-
'textarea'
|
|
212
|
-
].includes(type ?? '') && type) {
|
|
213
|
-
return streamText(options ?? {
|
|
214
|
-
action: 'Compose'
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
if (type === 'upload') {
|
|
183
|
+
if (field?.type === 'upload') {
|
|
218
184
|
return generateUpload();
|
|
219
185
|
}
|
|
186
|
+
// All supported types use structured object generation when schema is provided server-side
|
|
187
|
+
return streamObject(options ?? {
|
|
188
|
+
action: 'Compose'
|
|
189
|
+
});
|
|
220
190
|
}, [
|
|
221
191
|
generateUpload,
|
|
222
192
|
streamObject,
|
|
223
|
-
|
|
224
|
-
type
|
|
193
|
+
field
|
|
225
194
|
]);
|
|
226
195
|
const stop = useCallback(()=>{
|
|
227
196
|
console.log('Stopping...');
|
|
228
197
|
objectStop();
|
|
229
|
-
completionStop();
|
|
230
198
|
}, [
|
|
231
|
-
objectStop
|
|
232
|
-
completionStop
|
|
199
|
+
objectStop
|
|
233
200
|
]);
|
|
234
201
|
return {
|
|
235
202
|
generate,
|
|
236
|
-
isLoading:
|
|
203
|
+
isLoading: loadingObject,
|
|
237
204
|
stop
|
|
238
205
|
};
|
|
239
206
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/Compose/hooks/useGenerate.ts"],"sourcesContent":["import { useCompletion, experimental_useObject as useObject } from '@ai-sdk/react'\nimport { useEditorConfigContext } from '@payloadcms/richtext-lexical/client'\nimport { toast, useConfig, useDocumentInfo, useField, useForm, useLocale } from '@payloadcms/ui'\nimport { jsonSchema } from 'ai'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\n\nimport type { ActionMenuItems, GenerateTextarea } from '../../../types.js'\n\nimport {\n PLUGIN_API_ENDPOINT_GENERATE,\n PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_NAME,\n} from '../../../defaults.js'\nimport { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js'\nimport { editorSchemaValidator } from '../../../utilities/editorSchemaValidator.js'\nimport { setSafeLexicalState } from '../../../utilities/setSafeLexicalState.js'\nimport { useHistory } from './useHistory.js'\n\ntype ActionCallbackParams = { action: ActionMenuItems; params?: unknown }\n\nexport const useGenerate = ({ instructionId }: { instructionId: string }) => {\n // Create a ref to hold the current instructionId\n const instructionIdRef = useRef(instructionId)\n\n // Update the ref whenever instructionId changes\n useEffect(() => {\n instructionIdRef.current = instructionId\n }, [instructionId])\n\n const { type, path: pathFromContext } = useFieldProps()\n const editorConfigContext = useEditorConfigContext()\n\n const { editor } = editorConfigContext\n\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n\n const { setValue } = useField<string>({\n path: pathFromContext ?? '',\n })\n\n const { set: setHistory } = useHistory()\n\n const { getData } = useForm()\n const { id: documentId, collectionSlug } = useDocumentInfo()\n\n const localFromContext = useLocale()\n const {\n config: { collections },\n } = useConfig()\n\n const collection = collections.find((collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE)\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection?.admin ?? {}\n const { schema: editorSchema = {} } = editorConfig\n\n const memoizedValidator = useMemo(() => {\n return editorSchemaValidator(editorSchema)\n }, [editorSchema])\n\n const memoizedSchema = useMemo(\n () =>\n jsonSchema(editorSchema, {\n validate: (value) => {\n const isValid = memoizedValidator(value)\n\n if (isValid) {\n return {\n success: true,\n value,\n }\n } else {\n return {\n error: new Error('Invalid schema'),\n success: false,\n }\n }\n },\n }),\n [memoizedValidator],\n )\n\n const {\n isLoading: loadingObject,\n object,\n stop: objectStop,\n submit,\n } = useObject({\n api: `/api${PLUGIN_API_ENDPOINT_GENERATE}`,\n onError: (error: any) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error('Error generating object:', error)\n },\n onFinish: (result) => {\n if (result.object) {\n setHistory(result.object)\n setValue(result.object)\n } else {\n console.log('onFinish: result ', result)\n }\n },\n schema: memoizedSchema,\n })\n\n useEffect(() => {\n if (!object) {\n return\n }\n\n requestAnimationFrame(() => {\n // TODO: Temporary disabled pre validation, sometimes it fails to validate\n // const validateObject = await memoizedSchema?.validate?.(object)\n // if (validateObject?.success) {\n setSafeLexicalState(object, editor)\n // }\n })\n }, [object, editor])\n\n const {\n complete,\n completion,\n isLoading: loadingCompletion,\n stop: completionStop,\n } = useCompletion({\n api: `${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE}`,\n onError: (error: any) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error('Error generating text:', error)\n },\n onFinish: (prompt, result) => {\n setHistory(result)\n },\n streamProtocol: 'data',\n })\n\n useEffect(() => {\n if (!completion) {\n return\n }\n\n requestAnimationFrame(() => {\n setValue(completion)\n })\n }, [completion])\n\n const streamObject = useCallback(\n ({ action = 'Compose', params }: ActionCallbackParams) => {\n const doc = getData()\n\n const currentInstructionId = instructionIdRef.current\n\n const options = {\n action,\n actionParams: params,\n instructionId: currentInstructionId,\n }\n\n submit({\n allowedEditorNodes: Array.from(editor?._nodes?.keys() || []),\n doc: {\n ...doc,\n id: documentId,\n },\n locale: localFromContext?.code,\n options,\n })\n },\n [localFromContext?.code, instructionIdRef, documentId],\n )\n\n const streamText = useCallback(\n async ({ action = 'Compose', params }: ActionCallbackParams) => {\n const doc = getData()\n const currentInstructionId = instructionIdRef.current\n\n const options = {\n action,\n actionParams: params,\n instructionId: currentInstructionId,\n }\n\n await complete('', {\n body: {\n doc: {\n ...doc,\n id: documentId,\n },\n locale: localFromContext?.code,\n options,\n },\n })\n },\n [getData, localFromContext?.code, instructionIdRef, complete, documentId],\n )\n\n const generateUpload = useCallback(async () => {\n const doc = getData()\n const currentInstructionId = instructionIdRef.current\n\n return fetch(`${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE_UPLOAD}`, {\n body: JSON.stringify({\n collectionSlug: collectionSlug ?? '',\n doc,\n documentId,\n locale: localFromContext?.code,\n options: {\n instructionId: currentInstructionId,\n },\n } satisfies Parameters<GenerateTextarea>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n .then(async (uploadResponse) => {\n if (uploadResponse.ok) {\n const { result } = await uploadResponse.json()\n if (!result) {\n throw new Error('generateUpload: Something went wrong')\n }\n\n setValue(result?.id)\n setHistory(result?.id)\n console.log('Image updated...', result)\n } else {\n const { errors = [] } = await uploadResponse.json()\n const errStr = errors.map((error: any) => error.message).join(', ')\n throw new Error(errStr)\n }\n return uploadResponse\n })\n .catch((error) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error(\n 'Error generating or setting your upload, please set it manually if its saved in your media files.',\n error\n )\n })\n }, [getData, localFromContext?.code, instructionIdRef, setValue, documentId, collectionSlug])\n\n const generate = useCallback(\n async (options?: ActionCallbackParams) => {\n if (type === 'richText') {\n return streamObject(options ?? { action: 'Compose' })\n }\n\n if (['text', 'textarea'].includes(type ?? '') && type) {\n return streamText(options ?? { action: 'Compose' })\n }\n\n if (type === 'upload') {\n return generateUpload()\n }\n },\n [generateUpload, streamObject, streamText, type],\n )\n\n const stop = useCallback(() => {\n console.log('Stopping...')\n objectStop()\n completionStop()\n }, [objectStop, completionStop])\n\n return {\n generate,\n isLoading: loadingCompletion || loadingObject,\n stop,\n }\n}\n"],"names":["useCompletion","experimental_useObject","useObject","useEditorConfigContext","toast","useConfig","useDocumentInfo","useField","useForm","useLocale","jsonSchema","useCallback","useEffect","useMemo","useRef","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","useFieldProps","editorSchemaValidator","setSafeLexicalState","useHistory","useGenerate","instructionId","instructionIdRef","current","type","path","pathFromContext","editorConfigContext","editor","config","routes","api","serverURL","setValue","set","setHistory","getData","id","documentId","collectionSlug","localFromContext","collections","collection","find","slug","custom","editorConfig","admin","schema","editorSchema","memoizedValidator","memoizedSchema","validate","value","isValid","success","error","Error","isLoading","loadingObject","object","stop","objectStop","submit","onError","message","console","onFinish","result","log","requestAnimationFrame","complete","completion","loadingCompletion","completionStop","prompt","streamProtocol","streamObject","action","params","doc","currentInstructionId","options","actionParams","allowedEditorNodes","Array","from","_nodes","keys","locale","code","streamText","body","generateUpload","fetch","JSON","stringify","credentials","headers","method","then","uploadResponse","ok","json","errors","errStr","map","join","catch","generate","includes"],"mappings":"AAAA,SAASA,aAAa,EAAEC,0BAA0BC,SAAS,QAAQ,gBAAe;AAClF,SAASC,sBAAsB,QAAQ,sCAAqC;AAC5E,SAASC,KAAK,EAAEC,SAAS,EAAEC,eAAe,EAAEC,QAAQ,EAAEC,OAAO,EAAEC,SAAS,QAAQ,iBAAgB;AAChG,SAASC,UAAU,QAAQ,KAAI;AAC/B,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,MAAM,QAAQ,QAAO;AAI/D,SACEC,4BAA4B,EAC5BC,mCAAmC,EACnCC,yBAAyB,EACzBC,WAAW,QACN,uBAAsB;AAC7B,SAASC,aAAa,QAAQ,oDAAmD;AACjF,SAASC,qBAAqB,QAAQ,8CAA6C;AACnF,SAASC,mBAAmB,QAAQ,4CAA2C;AAC/E,SAASC,UAAU,QAAQ,kBAAiB;AAI5C,OAAO,MAAMC,cAAc,CAAC,EAAEC,aAAa,EAA6B;IACtE,iDAAiD;IACjD,MAAMC,mBAAmBX,OAAOU;IAEhC,gDAAgD;IAChDZ,UAAU;QACRa,iBAAiBC,OAAO,GAAGF;IAC7B,GAAG;QAACA;KAAc;IAElB,MAAM,EAAEG,IAAI,EAAEC,MAAMC,eAAe,EAAE,GAAGV;IACxC,MAAMW,sBAAsB3B;IAE5B,MAAM,EAAE4B,MAAM,EAAE,GAAGD;IAEnB,MAAM,EAAEE,MAAM,EAAE,GAAG3B;IACnB,MAAM,EACJ4B,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,GAAGH;IAEJ,MAAM,EAAEI,QAAQ,EAAE,GAAG7B,SAAiB;QACpCqB,MAAMC,mBAAmB;IAC3B;IAEA,MAAM,EAAEQ,KAAKC,UAAU,EAAE,GAAGhB;IAE5B,MAAM,EAAEiB,OAAO,EAAE,GAAG/B;IACpB,MAAM,EAAEgC,IAAIC,UAAU,EAAEC,cAAc,EAAE,GAAGpC;IAE3C,MAAMqC,mBAAmBlC;IACzB,MAAM,EACJuB,QAAQ,EAAEY,WAAW,EAAE,EACxB,GAAGvC;IAEJ,MAAMwC,aAAaD,YAAYE,IAAI,CAAC,CAACD,aAAeA,WAAWE,IAAI,KAAK9B;IACxE,MAAM,EAAE+B,QAAQ,EAAE,CAAC9B,YAAY,EAAE,EAAE+B,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAGJ,YAAYK,SAAS,CAAC;IAC7F,MAAM,EAAEC,QAAQC,eAAe,CAAC,CAAC,EAAE,GAAGH;IAEtC,MAAMI,oBAAoBxC,QAAQ;QAChC,OAAOO,sBAAsBgC;IAC/B,GAAG;QAACA;KAAa;IAEjB,MAAME,iBAAiBzC,QACrB,IACEH,WAAW0C,cAAc;YACvBG,UAAU,CAACC;gBACT,MAAMC,UAAUJ,kBAAkBG;gBAElC,IAAIC,SAAS;oBACX,OAAO;wBACLC,SAAS;wBACTF;oBACF;gBACF,OAAO;oBACL,OAAO;wBACLG,OAAO,IAAIC,MAAM;wBACjBF,SAAS;oBACX;gBACF;YACF;QACF,IACF;QAACL;KAAkB;IAGrB,MAAM,EACJQ,WAAWC,aAAa,EACxBC,MAAM,EACNC,MAAMC,UAAU,EAChBC,MAAM,EACP,GAAGhE,UAAU;QACZgC,KAAK,CAAC,IAAI,EAAEnB,8BAA8B;QAC1CoD,SAAS,CAACR;YACRvD,MAAMuD,KAAK,CAAC,CAAC,oBAAoB,EAAEA,MAAMS,OAAO,EAAE;YAClDC,QAAQV,KAAK,CAAC,4BAA4BA;QAC5C;QACAW,UAAU,CAACC;YACT,IAAIA,OAAOR,MAAM,EAAE;gBACjBzB,WAAWiC,OAAOR,MAAM;gBACxB3B,SAASmC,OAAOR,MAAM;YACxB,OAAO;gBACLM,QAAQG,GAAG,CAAC,qBAAqBD;YACnC;QACF;QACApB,QAAQG;IACV;IAEA1C,UAAU;QACR,IAAI,CAACmD,QAAQ;YACX;QACF;QAEAU,sBAAsB;YACpB,0EAA0E;YAC1E,kEAAkE;YAClE,iCAAiC;YAC/BpD,oBAAoB0C,QAAQhC;QAC9B,IAAI;QACN;IACF,GAAG;QAACgC;QAAQhC;KAAO;IAEnB,MAAM,EACJ2C,QAAQ,EACRC,UAAU,EACVd,WAAWe,iBAAiB,EAC5BZ,MAAMa,cAAc,EACrB,GAAG7E,cAAc;QAChBkC,KAAK,GAAGC,YAAYD,MAAMnB,8BAA8B;QACxDoD,SAAS,CAACR;YACRvD,MAAMuD,KAAK,CAAC,CAAC,oBAAoB,EAAEA,MAAMS,OAAO,EAAE;YAClDC,QAAQV,KAAK,CAAC,0BAA0BA;QAC1C;QACAW,UAAU,CAACQ,QAAQP;YACjBjC,WAAWiC;QACb;QACAQ,gBAAgB;IAClB;IAEAnE,UAAU;QACR,IAAI,CAAC+D,YAAY;YACf;QACF;QAEAF,sBAAsB;YACpBrC,SAASuC;QACX;IACF,GAAG;QAACA;KAAW;IAEf,MAAMK,eAAerE,YACnB,CAAC,EAAEsE,SAAS,SAAS,EAAEC,MAAM,EAAwB;QACnD,MAAMC,MAAM5C;QAEZ,MAAM6C,uBAAuB3D,iBAAiBC,OAAO;QAErD,MAAM2D,UAAU;YACdJ;YACAK,cAAcJ;YACd1D,eAAe4D;QACjB;QAEAlB,OAAO;YACLqB,oBAAoBC,MAAMC,IAAI,CAAC1D,QAAQ2D,QAAQC,UAAU,EAAE;YAC3DR,KAAK;gBACH,GAAGA,GAAG;gBACN3C,IAAIC;YACN;YACAmD,QAAQjD,kBAAkBkD;YAC1BR;QACF;IACF,GACA;QAAC1C,kBAAkBkD;QAAMpE;QAAkBgB;KAAW;IAGxD,MAAMqD,aAAanF,YACjB,OAAO,EAAEsE,SAAS,SAAS,EAAEC,MAAM,EAAwB;QACzD,MAAMC,MAAM5C;QACZ,MAAM6C,uBAAuB3D,iBAAiBC,OAAO;QAErD,MAAM2D,UAAU;YACdJ;YACAK,cAAcJ;YACd1D,eAAe4D;QACjB;QAEA,MAAMV,SAAS,IAAI;YACjBqB,MAAM;gBACJZ,KAAK;oBACH,GAAGA,GAAG;oBACN3C,IAAIC;gBACN;gBACAmD,QAAQjD,kBAAkBkD;gBAC1BR;YACF;QACF;IACF,GACA;QAAC9C;QAASI,kBAAkBkD;QAAMpE;QAAkBiD;QAAUjC;KAAW;IAG3E,MAAMuD,iBAAiBrF,YAAY;QACjC,MAAMwE,MAAM5C;QACZ,MAAM6C,uBAAuB3D,iBAAiBC,OAAO;QAErD,OAAOuE,MAAM,GAAG9D,YAAYD,MAAMlB,qCAAqC,EAAE;YACvE+E,MAAMG,KAAKC,SAAS,CAAC;gBACnBzD,gBAAgBA,kBAAkB;gBAClCyC;gBACA1C;gBACAmD,QAAQjD,kBAAkBkD;gBAC1BR,SAAS;oBACP7D,eAAe4D;gBACjB;YACF;YACAgB,aAAa;YACbC,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;QACV,GACGC,IAAI,CAAC,OAAOC;YACX,IAAIA,eAAeC,EAAE,EAAE;gBACrB,MAAM,EAAElC,MAAM,EAAE,GAAG,MAAMiC,eAAeE,IAAI;gBAC5C,IAAI,CAACnC,QAAQ;oBACX,MAAM,IAAIX,MAAM;gBAClB;gBAEAxB,SAASmC,QAAQ/B;gBACjBF,WAAWiC,QAAQ/B;gBACnB6B,QAAQG,GAAG,CAAC,oBAAoBD;YAClC,OAAO;gBACL,MAAM,EAAEoC,SAAS,EAAE,EAAE,GAAG,MAAMH,eAAeE,IAAI;gBACjD,MAAME,SAASD,OAAOE,GAAG,CAAC,CAAClD,QAAeA,MAAMS,OAAO,EAAE0C,IAAI,CAAC;gBAC9D,MAAM,IAAIlD,MAAMgD;YAClB;YACA,OAAOJ;QACT,GACCO,KAAK,CAAC,CAACpD;YACNvD,MAAMuD,KAAK,CAAC,CAAC,oBAAoB,EAAEA,MAAMS,OAAO,EAAE;YAClDC,QAAQV,KAAK,CACX,qGACAA;QAEJ;IACJ,GAAG;QAACpB;QAASI,kBAAkBkD;QAAMpE;QAAkBW;QAAUK;QAAYC;KAAe;IAE5F,MAAMsE,WAAWrG,YACf,OAAO0E;QACL,IAAI1D,SAAS,YAAY;YACvB,OAAOqD,aAAaK,WAAW;gBAAEJ,QAAQ;YAAU;QACrD;QAEA,IAAI;YAAC;YAAQ;SAAW,CAACgC,QAAQ,CAACtF,QAAQ,OAAOA,MAAM;YACrD,OAAOmE,WAAWT,WAAW;gBAAEJ,QAAQ;YAAU;QACnD;QAEA,IAAItD,SAAS,UAAU;YACrB,OAAOqE;QACT;IACF,GACA;QAACA;QAAgBhB;QAAcc;QAAYnE;KAAK;IAGlD,MAAMqC,OAAOrD,YAAY;QACvB0D,QAAQG,GAAG,CAAC;QACZP;QACAY;IACF,GAAG;QAACZ;QAAYY;KAAe;IAE/B,OAAO;QACLmC;QACAnD,WAAWe,qBAAqBd;QAChCE;IACF;AACF,EAAC"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/Compose/hooks/useGenerate.ts"],"sourcesContent":["import { experimental_useObject as useObject } from '@ai-sdk/react'\nimport { useEditorConfigContext } from '@payloadcms/richtext-lexical/client'\nimport { toast, useConfig, useDocumentInfo, useField, useForm, useLocale } from '@payloadcms/ui'\nimport { jsonSchema } from 'ai'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\n\nimport type { ActionMenuItems, GenerateTextarea } from '../../../types.js'\n\nimport {\n PLUGIN_API_ENDPOINT_GENERATE,\n PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_NAME,\n} from '../../../defaults.js'\nimport { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js'\nimport { editorSchemaValidator } from '../../../utilities/editorSchemaValidator.js'\nimport { fieldToJsonSchema } from '../../../utilities/fieldToJsonSchema.js'\nimport { setSafeLexicalState } from '../../../utilities/setSafeLexicalState.js'\nimport { useHistory } from './useHistory.js'\n\ntype ActionCallbackParams = { action: ActionMenuItems; params?: unknown }\n\nexport const useGenerate = ({ instructionId }: { instructionId: string }) => {\n // Create a ref to hold the current instructionId\n const instructionIdRef = useRef(instructionId)\n\n // Update the ref whenever instructionId changes\n useEffect(() => {\n instructionIdRef.current = instructionId\n }, [instructionId])\n\n const { field, path: pathFromContext } = useFieldProps()\n const editorConfigContext = useEditorConfigContext()\n\n const { editor } = editorConfigContext\n\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n\n const { setValue } = useField<any>({\n path: pathFromContext ?? '',\n })\n\n const { set: setHistory } = useHistory()\n\n const { getData } = useForm()\n const { id: documentId, collectionSlug } = useDocumentInfo()\n\n const localFromContext = useLocale()\n const {\n config: { collections },\n } = useConfig()\n\n const collection = collections.find((collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE)\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection?.admin ?? {}\n const { schema: editorSchema = {} } = editorConfig\n\n const memoizedValidator = useMemo(() => {\n return editorSchemaValidator(editorSchema)\n }, [editorSchema])\n\n const memoizedSchema = useMemo(\n () =>\n jsonSchema(editorSchema, {\n validate: (value) => {\n const isValid = memoizedValidator(value)\n\n if (isValid) {\n return {\n success: true,\n value,\n }\n } else {\n return {\n error: new Error('Invalid schema'),\n success: false,\n }\n }\n },\n }),\n [memoizedValidator],\n )\n\n // Active JSON schema for useObject based on field type\n const activeSchema = useMemo(() => {\n const f = field as any\n const fieldType = f?.type as string | undefined\n if (fieldType === 'richText') {\n return memoizedSchema\n }\n if (f && f.name && fieldType) {\n const schemaJson = fieldToJsonSchema(f)\n if (schemaJson && Object.keys(schemaJson).length > 0) {\n return jsonSchema(schemaJson)\n }\n }\n return undefined\n }, [field, memoizedSchema])\n\n const {\n isLoading: loadingObject,\n object,\n stop: objectStop,\n submit,\n } = useObject({\n api: `/api${PLUGIN_API_ENDPOINT_GENERATE}`,\n onError: (error: any) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error('Error generating object:', error)\n },\n onFinish: (result) => {\n if (result.object && field) {\n if (field.type === 'richText') {\n setHistory(result.object)\n setValue(result.object)\n } else if ('name' in field) {\n setHistory(result.object[field.name])\n setValue(result.object[field.name])\n }\n } else {\n console.log('onFinish: result, field ', result, field)\n }\n },\n schema: activeSchema as any,\n })\n\n useEffect(() => {\n if (!object) {\n return\n }\n\n requestAnimationFrame(() => {\n if (field?.type === 'richText') {\n setSafeLexicalState(object, editor)\n } else if (field && 'name' in field && object[field.name]) {\n setValue(object[field.name])\n }\n })\n }, [object, editor, field])\n\n const streamObject = useCallback(\n ({ action = 'Compose', params }: ActionCallbackParams) => {\n const doc = getData()\n\n const currentInstructionId = instructionIdRef.current\n\n const options = {\n action,\n actionParams: params,\n instructionId: currentInstructionId,\n }\n\n submit({\n allowedEditorNodes: Array.from(editor?._nodes?.keys() || []),\n doc: {\n ...doc,\n id: documentId,\n },\n locale: localFromContext?.code,\n options,\n })\n },\n [localFromContext?.code, instructionIdRef, documentId],\n )\n\n const generateUpload = useCallback(async () => {\n const doc = getData()\n const currentInstructionId = instructionIdRef.current\n\n return fetch(`${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE_UPLOAD}`, {\n body: JSON.stringify({\n collectionSlug: collectionSlug ?? '',\n doc,\n documentId,\n locale: localFromContext?.code,\n options: {\n instructionId: currentInstructionId,\n },\n } satisfies Parameters<GenerateTextarea>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n .then(async (uploadResponse) => {\n if (uploadResponse.ok) {\n const { result } = await uploadResponse.json()\n if (!result) {\n throw new Error('generateUpload: Something went wrong')\n }\n\n setValue(result?.id)\n setHistory(result?.id)\n console.log('Image updated...', result)\n } else {\n const { errors = [] } = await uploadResponse.json()\n const errStr = errors.map((error: any) => error.message).join(', ')\n throw new Error(errStr)\n }\n return uploadResponse\n })\n .catch((error) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error(\n 'Error generating or setting your upload, please set it manually if its saved in your media files.',\n error,\n )\n })\n }, [getData, localFromContext?.code, instructionIdRef, setValue, documentId, collectionSlug])\n\n const generate = useCallback(\n async (options?: ActionCallbackParams) => {\n if ((field as any)?.type === 'upload') {\n return generateUpload()\n }\n // All supported types use structured object generation when schema is provided server-side\n return streamObject(options ?? { action: 'Compose' })\n },\n [generateUpload, streamObject, field],\n )\n\n const stop = useCallback(() => {\n console.log('Stopping...')\n objectStop()\n }, [objectStop])\n\n return {\n generate,\n isLoading: loadingObject,\n stop,\n }\n}\n"],"names":["experimental_useObject","useObject","useEditorConfigContext","toast","useConfig","useDocumentInfo","useField","useForm","useLocale","jsonSchema","useCallback","useEffect","useMemo","useRef","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","useFieldProps","editorSchemaValidator","fieldToJsonSchema","setSafeLexicalState","useHistory","useGenerate","instructionId","instructionIdRef","current","field","path","pathFromContext","editorConfigContext","editor","config","routes","api","serverURL","setValue","set","setHistory","getData","id","documentId","collectionSlug","localFromContext","collections","collection","find","slug","custom","editorConfig","admin","schema","editorSchema","memoizedValidator","memoizedSchema","validate","value","isValid","success","error","Error","activeSchema","f","fieldType","type","name","schemaJson","Object","keys","length","undefined","isLoading","loadingObject","object","stop","objectStop","submit","onError","message","console","onFinish","result","log","requestAnimationFrame","streamObject","action","params","doc","currentInstructionId","options","actionParams","allowedEditorNodes","Array","from","_nodes","locale","code","generateUpload","fetch","body","JSON","stringify","credentials","headers","method","then","uploadResponse","ok","json","errors","errStr","map","join","catch","generate"],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from './icons.module.css';
|
|
3
|
+
import LottieAnimation from './LottieAnimation.js';
|
|
4
|
+
export const PluginIcon = ({ color = 'white', isLoading, }) => {
|
|
5
|
+
return (<span className={styles.actions_icon}>
|
|
6
|
+
<LottieAnimation isLoading={isLoading}/>
|
|
7
|
+
</span>);
|
|
8
|
+
};
|
|
9
|
+
export const TuneIcon = ({ color = 'white', size = 24 }) => {
|
|
10
|
+
return (<span className={styles.icon}>
|
|
11
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
12
|
+
<path d="M450-130v-220h60v80h320v60H510v80h-60Zm-320-80v-60h220v60H130Zm160-160v-80H130v-60h160v-80h60v220h-60Zm160-80v-60h380v60H450Zm160-160v-220h60v80h160v60H670v80h-60Zm-480-80v-60h380v60H130Z"/>
|
|
13
|
+
</svg>
|
|
14
|
+
</span>);
|
|
15
|
+
};
|
|
16
|
+
export const LocalLibraryIcon = ({ color = 'white', size = 24 }) => {
|
|
17
|
+
return (<span className={styles.icon}>
|
|
18
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
19
|
+
<path d="M480-115.38q-67.38-54.93-148.85-86.7Q249.69-233.85 160-240v-373.85q91.77 5.39 174.38 43.81Q417-531.62 480-474.92q63-56.7 145.62-95.12 82.61-38.42 174.38-43.81V-240q-89.92 6.15-171.27 37.92-81.35 31.77-148.73 86.7Zm0-50.16q63-46.23 134-74.56 71-28.33 146-37.44v-291.38q-78.38 13-149.65 50.57-71.27 37.58-130.35 96.66-59.08-59.08-130.35-96.66-71.27-37.57-149.65-50.57v291.38q75 9.11 146 37.44t134 74.56Zm0-451.38q-53.31 0-91.27-37.96-37.96-37.97-37.96-91.27 0-53.31 37.96-91.27 37.96-37.96 91.27-37.96 53.31 0 91.27 37.96 37.96 37.96 37.96 91.27 0 53.3-37.96 91.27-37.96 37.96-91.27 37.96Zm.03-40q36.82 0 63.01-26.22 26.19-26.22 26.19-63.04t-26.22-63.01q-26.22-26.19-63.04-26.19t-63.01 26.21q-26.19 26.22-26.19 63.04t26.22 63.01q26.22 26.2 63.04 26.2Zm-.03-89.23Zm0 324.46Z"/>
|
|
20
|
+
</svg>
|
|
21
|
+
</span>);
|
|
22
|
+
};
|
|
23
|
+
export const SpellCheckIcon = ({ color = 'white', size = 24 }) => {
|
|
24
|
+
return (<span className={styles.icon}>
|
|
25
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
26
|
+
<path d="M564-93.85 407.85-250 450-292.15l114 114 226.77-226.77 42.15 42.15L564-93.85ZM135.39-320l191.69-520h69.38l190.92 520h-68.92l-49.07-142H250.92l-49.84 142h-65.69ZM272-518h178.31L362-765.54h-3.23L272-518Z"/>
|
|
27
|
+
</svg>
|
|
28
|
+
</span>);
|
|
29
|
+
};
|
|
30
|
+
export const TranslateIcon = ({ color = 'white', size = 24 }) => {
|
|
31
|
+
return (<span className={styles.icon}>
|
|
32
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
33
|
+
<path d="m476-100 178.15-460h62.46l178.16 460h-63.62l-45.3-122H584.92l-45.31 122H476ZM160.38-217.69l-42.15-42.16 198.92-199.3q-34.61-35-65.8-83.08Q220.15-590.31 200-640h63.61q17.31 36.31 42.12 72.62 24.81 36.3 53.58 66.07 42.61-43 80.61-104.42T493.62-720H67.69v-60H330v-64.61h60V-780h262.31v60h-97.93q-19.46 67.38-62.03 140.88-42.58 73.5-90.89 121.2l98.69 101.07-22.69 61.62-118.15-121.16-198.93 198.7Zm443.77-57.39h162.46l-81.23-218.23-81.23 218.23Z"/>
|
|
34
|
+
</svg>
|
|
35
|
+
</span>);
|
|
36
|
+
};
|
|
37
|
+
export const DocsAddOnIcon = ({ color = 'white', size = 24 }) => {
|
|
38
|
+
return (<span className={styles.icon}>
|
|
39
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
40
|
+
<path d="M650-131v-120H530v-60h120v-120h60v120h120v60H710v120h-60ZM170-250v-60h281.85q-1.85 15.8-1.35 30.09t2.35 29.91H170Zm0-160v-60h379.08q-17.23 12.15-31.5 27.15-14.27 15-25.96 32.85H170Zm0-160v-60h580v60H170Zm0-160v-60h580v60H170Z"/>
|
|
41
|
+
</svg>
|
|
42
|
+
</span>);
|
|
43
|
+
};
|
|
44
|
+
export const SummarizeIcon = ({ color = 'white', size = 24 }) => {
|
|
45
|
+
return (<span className={styles.icon}>
|
|
46
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
47
|
+
<path d="M320-603.85q15.08 0 25.62-10.53 10.53-10.54 10.53-25.62 0-15.08-10.53-25.62-10.54-10.53-25.62-10.53-15.08 0-25.62 10.53-10.53 10.54-10.53 25.62 0 15.08 10.53 25.62 10.54 10.53 25.62 10.53Zm0 160q15.08 0 25.62-10.53 10.53-10.54 10.53-25.62 0-15.08-10.53-25.62-10.54-10.53-25.62-10.53-15.08 0-25.62 10.53-10.53 10.54-10.53 25.62 0 15.08 10.53 25.62 10.54 10.53 25.62 10.53Zm0 160q15.08 0 25.62-10.53 10.53-10.54 10.53-25.62 0-15.08-10.53-25.62-10.54-10.53-25.62-10.53-15.08 0-25.62 10.53-10.53 10.54-10.53 25.62 0 15.08 10.53 25.62 10.54 10.53 25.62 10.53ZM212.31-140Q182-140 161-161q-21-21-21-51.31v-535.38Q140-778 161-799q21-21 51.31-21h419.23L820-631.54v419.23Q820-182 799-161q-21 21-51.31 21H212.31Zm0-60h535.38q5.39 0 8.85-3.46t3.46-8.85V-600H600v-160H212.31q-5.39 0-8.85 3.46t-3.46 8.85v535.38q0 5.39 3.46 8.85t8.85 3.46ZM200-760v160-160V-200v-560Z"/>
|
|
48
|
+
</svg>
|
|
49
|
+
</span>);
|
|
50
|
+
};
|
|
51
|
+
export const SegmentIcon = ({ color = 'white', size = 24 }) => {
|
|
52
|
+
return (<span className={styles.icon}>
|
|
53
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
54
|
+
<path d="M380-254.62v-59.99h440v59.99H380ZM380-450v-60h440v60H380ZM140-645.39v-59.99h680v59.99H140Z"/>
|
|
55
|
+
</svg>
|
|
56
|
+
</span>);
|
|
57
|
+
};
|
|
58
|
+
export const StylusNoteIcon = ({ color = 'white', size = 24 }) => {
|
|
59
|
+
return (<span className={styles.icon}>
|
|
60
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
61
|
+
<path d="m487.46-283.15 332.31-332.31q2.69-2.69 2.69-6.54t-2.69-6.54l-38.92-38.92q-2.7-2.69-6.54-2.69-3.85 0-6.54 2.69L435.46-335.15l52 52Zm-251 72.38q-89.23-5-134-39.69-44.77-34.69-44.77-98.16 0-60.76 51-98.57 51-37.81 141.77-45.81 43.62-3.77 65.43-15.77 21.8-12 21.8-33.23 0-29.46-29.5-44.96t-96.73-22.27l5.46-59.62q92.23 8.77 136.5 39.77 44.27 31 44.27 87.08 0 47.61-36.57 75.5-36.58 27.88-106.2 33.5-68.61 5.77-102.92 26.77t-34.31 57.61q0 37.31 28.58 55.51 28.58 18.19 92.65 22.34l-2.46 60Zm260.38 3.15L359.92-344.54l373.54-373.15q17.69-17.69 41.35-17.5 23.65.19 41.34 17.5L870-663.85q17.69 17.7 17.69 41.54 0 23.85-17.69 41.54L496.84-207.62ZM363.23-180q-13.54 3.23-23.84-7.08-10.31-10.31-7.08-23.84l27.61-133.62 136.92 136.92L363.23-180Z"/>
|
|
62
|
+
</svg>
|
|
63
|
+
</span>);
|
|
64
|
+
};
|
|
65
|
+
export const EditNoteIcon = ({ color = 'white', size = 24 }) => {
|
|
66
|
+
return (<span className={styles.icon}>
|
|
67
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
68
|
+
<path d="M180-400v-60h280v60H180Zm0-160v-60h440v60H180Zm0-160v-60h440v60H180Zm344.62 540v-105.69l217.15-216.16q7.46-7.46 16.11-10.5 8.65-3.03 17.3-3.03 9.43 0 18.25 3.53 8.82 3.54 16.03 10.62l37 37.38q6.46 7.47 10 16.16Q860-439 860-430.31t-3.23 17.69q-3.23 9-10.31 16.46L630.31-180H524.62Zm287.69-250.31-37-37.38 37 37.38Zm-240 202.62h38l129.84-130.47-18.38-19-18.62-18.76-130.84 130.23v38Zm149.46-149.47-18.62-18.76 37 37.76-18.38-19Z"/>
|
|
69
|
+
</svg>
|
|
70
|
+
</span>);
|
|
71
|
+
};
|
|
72
|
+
export const ArrowIcon = ({ color = 'white', size = 24 }) => {
|
|
73
|
+
return (<span className={styles.icon}>
|
|
74
|
+
<svg height={size} viewBox="0 -960 960 960" width={size} xmlns="http://www.w3.org/2000/svg">
|
|
75
|
+
<path d="m531.69-480-184-184L376-692.31 588.31-480 376-267.69 347.69-296l184-184Z"/>
|
|
76
|
+
</svg>
|
|
77
|
+
</span>);
|
|
78
|
+
};
|