@automattic/jetpack-ai-client 0.12.4 → 0.13.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.
- package/CHANGELOG.md +9 -0
- package/build/components/ai-control/ai-control.d.ts +2 -1
- package/build/components/ai-control/ai-control.js +2 -2
- package/build/components/ai-control/extension-ai-control.d.ts +2 -1
- package/build/components/ai-control/extension-ai-control.js +2 -2
- package/build/hooks/use-image-generator/index.d.ts +2 -1
- package/build/hooks/use-image-generator/index.js +68 -15
- package/package.json +18 -18
- package/src/components/ai-control/ai-control.tsx +3 -1
- package/src/components/ai-control/extension-ai-control.tsx +3 -0
- package/src/hooks/use-image-generator/index.ts +72 -15
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.13.0] - 2024-05-06
|
|
9
|
+
### Added
|
|
10
|
+
- AI Client: Add wrapper ref to AI Control. [#37145]
|
|
11
|
+
- AI Featured Image: Support custom user prompt on the image generation. [#37086]
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Updated package dependencies. [#37147] [#37148] [#37160]
|
|
15
|
+
|
|
8
16
|
## [0.12.4] - 2024-04-29
|
|
9
17
|
### Added
|
|
10
18
|
- AI Client: Export ExtensionAIControl. [#37087]
|
|
@@ -298,6 +306,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
298
306
|
- Updated package dependencies. [#31659]
|
|
299
307
|
- Updated package dependencies. [#31785]
|
|
300
308
|
|
|
309
|
+
[0.13.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.12.4...v0.13.0
|
|
301
310
|
[0.12.4]: https://github.com/Automattic/jetpack-ai-client/compare/v0.12.3...v0.12.4
|
|
302
311
|
[0.12.3]: https://github.com/Automattic/jetpack-ai-client/compare/v0.12.2...v0.12.3
|
|
303
312
|
[0.12.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.12.1...v0.12.2
|
|
@@ -17,6 +17,7 @@ type AIControlProps = {
|
|
|
17
17
|
actions?: ReactElement;
|
|
18
18
|
message?: ReactElement;
|
|
19
19
|
promptUserInputRef?: React.MutableRefObject<HTMLInputElement>;
|
|
20
|
+
wrapperRef?: React.MutableRefObject<HTMLDivElement | null>;
|
|
20
21
|
};
|
|
21
22
|
/**
|
|
22
23
|
* Base AIControl component. Contains the main structure of the control component and slots for banner, error, actions and message.
|
|
@@ -24,5 +25,5 @@ type AIControlProps = {
|
|
|
24
25
|
* @param {AIControlProps} props - Component props
|
|
25
26
|
* @returns {ReactElement} Rendered component
|
|
26
27
|
*/
|
|
27
|
-
export default function AIControl({ disabled, value, placeholder, isTransparent, state, onChange, banner, error, actions, message, promptUserInputRef, }: AIControlProps): ReactElement;
|
|
28
|
+
export default function AIControl({ disabled, value, placeholder, isTransparent, state, onChange, banner, error, actions, message, promptUserInputRef, wrapperRef, }: AIControlProps): ReactElement;
|
|
28
29
|
export {};
|
|
@@ -15,8 +15,8 @@ import './style.scss';
|
|
|
15
15
|
* @param {AIControlProps} props - Component props
|
|
16
16
|
* @returns {ReactElement} Rendered component
|
|
17
17
|
*/
|
|
18
|
-
export default function AIControl({ disabled = false, value = '', placeholder = '', isTransparent = false, state = 'init', onChange, banner = null, error = null, actions = null, message = null, promptUserInputRef = null, }) {
|
|
19
|
-
return (_jsxs("div", { className: "jetpack-components-ai-control__container-wrapper", children: [error, _jsxs("div", { className: "jetpack-components-ai-control__container", children: [banner, _jsxs("div", { className: classNames('jetpack-components-ai-control__wrapper', {
|
|
18
|
+
export default function AIControl({ disabled = false, value = '', placeholder = '', isTransparent = false, state = 'init', onChange, banner = null, error = null, actions = null, message = null, promptUserInputRef = null, wrapperRef = null, }) {
|
|
19
|
+
return (_jsxs("div", { className: "jetpack-components-ai-control__container-wrapper", ref: wrapperRef, children: [error, _jsxs("div", { className: "jetpack-components-ai-control__container", children: [banner, _jsxs("div", { className: classNames('jetpack-components-ai-control__wrapper', {
|
|
20
20
|
'is-transparent': isTransparent,
|
|
21
21
|
}), children: [_jsx(AiStatusIndicator, { state: state }), _jsx("div", { className: "jetpack-components-ai-control__input-wrapper", children: _jsx(PlainText, { value: value, onChange: onChange, placeholder: placeholder, className: "jetpack-components-ai-control__input", disabled: disabled, ref: promptUserInputRef }) }), actions] }), message] })] }));
|
|
22
22
|
}
|
|
@@ -16,6 +16,7 @@ type ExtensionAIControlProps = {
|
|
|
16
16
|
error?: string;
|
|
17
17
|
requestsRemaining?: number;
|
|
18
18
|
showUpgradeMessage?: boolean;
|
|
19
|
+
wrapperRef?: React.MutableRefObject<HTMLDivElement | null>;
|
|
19
20
|
onChange?: (newValue: string) => void;
|
|
20
21
|
onSend?: (currentValue: string) => void;
|
|
21
22
|
onStop?: () => void;
|
|
@@ -30,6 +31,6 @@ type ExtensionAIControlProps = {
|
|
|
30
31
|
* @param {React.MutableRefObject} ref - Ref to the component
|
|
31
32
|
* @returns {ReactElement} Rendered component
|
|
32
33
|
*/
|
|
33
|
-
export declare function ExtensionAIControl({ disabled, value, placeholder, showButtonLabels, isTransparent, state, showGuideLine, error, requestsRemaining, showUpgradeMessage, onChange, onSend, onStop, onClose, onUndo, onUpgrade, }: ExtensionAIControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
|
|
34
|
+
export declare function ExtensionAIControl({ disabled, value, placeholder, showButtonLabels, isTransparent, state, showGuideLine, error, requestsRemaining, showUpgradeMessage, wrapperRef, onChange, onSend, onStop, onClose, onUndo, onUpgrade, }: ExtensionAIControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
|
|
34
35
|
declare const _default: React.ForwardRefExoticComponent<ExtensionAIControlProps & React.RefAttributes<HTMLInputElement>>;
|
|
35
36
|
export default _default;
|
|
@@ -21,7 +21,7 @@ import './style.scss';
|
|
|
21
21
|
* @param {React.MutableRefObject} ref - Ref to the component
|
|
22
22
|
* @returns {ReactElement} Rendered component
|
|
23
23
|
*/
|
|
24
|
-
export function ExtensionAIControl({ disabled = false, value = '', placeholder = '', showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, error, requestsRemaining, showUpgradeMessage = false, onChange, onSend, onStop, onClose, onUndo, onUpgrade, }, ref) {
|
|
24
|
+
export function ExtensionAIControl({ disabled = false, value = '', placeholder = '', showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, error, requestsRemaining, showUpgradeMessage = false, wrapperRef, onChange, onSend, onStop, onClose, onUndo, onUpgrade, }, ref) {
|
|
25
25
|
const loading = state === 'requesting' || state === 'suggesting';
|
|
26
26
|
const [editRequest, setEditRequest] = useState(false);
|
|
27
27
|
const [lastValue, setLastValue] = useState(value || null);
|
|
@@ -81,6 +81,6 @@ export function ExtensionAIControl({ disabled = false, value = '', placeholder =
|
|
|
81
81
|
else if (showGuideLine) {
|
|
82
82
|
message = _jsx(GuidelineMessage, {});
|
|
83
83
|
}
|
|
84
|
-
return (_jsx(AIControl, { disabled: disabled || loading, value: value, placeholder: placeholder, isTransparent: isTransparent, state: state, onChange: changeHandler, actions: actions, message: message, promptUserInputRef: promptUserInputRef }));
|
|
84
|
+
return (_jsx(AIControl, { disabled: disabled || loading, value: value, placeholder: placeholder, isTransparent: isTransparent, state: state, onChange: changeHandler, actions: actions, message: message, promptUserInputRef: promptUserInputRef, wrapperRef: wrapperRef }));
|
|
85
85
|
}
|
|
86
86
|
export default forwardRef(ExtensionAIControl);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
declare const useImageGenerator: () => {
|
|
2
|
-
generateImage: ({ feature, postContent, responseFormat, }: {
|
|
2
|
+
generateImage: ({ feature, postContent, responseFormat, userPrompt, }: {
|
|
3
3
|
feature: string;
|
|
4
4
|
postContent: string;
|
|
5
5
|
responseFormat?: 'url' | 'b64_json';
|
|
6
|
+
userPrompt?: string;
|
|
6
7
|
}) => Promise<{
|
|
7
8
|
data: {
|
|
8
9
|
[key: string]: string;
|
|
@@ -7,20 +7,57 @@ import debugFactory from 'debug';
|
|
|
7
7
|
*/
|
|
8
8
|
import requestJwt from '../../jwt/index.js';
|
|
9
9
|
const debug = debugFactory('ai-client:use-image-generator');
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Cut the post content on a given lenght so the total length of the prompt is not longer than 4000 characters.
|
|
12
|
+
* @param {string} content - the content to be truncated
|
|
13
|
+
* @param {number} currentPromptLength - the length of the prompt already in use
|
|
14
|
+
* @returns {string} a truncated version of the content respecting the prompt length limit
|
|
15
|
+
*/
|
|
16
|
+
const truncateContent = (content, currentPromptLength) => {
|
|
17
|
+
const maxLength = 4000;
|
|
18
|
+
const remainingLength = maxLength - currentPromptLength;
|
|
19
|
+
// 6 is the length of the ellipsis and the space before it
|
|
20
|
+
return content.length > remainingLength
|
|
21
|
+
? content.substring(0, remainingLength - 6) + ` [...]`
|
|
22
|
+
: content;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Create the prompt string based on the provided context.
|
|
26
|
+
* @param {string} postContent - the content of the post
|
|
27
|
+
* @param {string} userPrompt - the user prompt for the image generation, if provided. Max length is 1000 characters, will be truncated.
|
|
28
|
+
* @returns {string} the prompt string
|
|
29
|
+
*/
|
|
30
|
+
const getImageGenerationPrompt = (postContent, userPrompt) => {
|
|
31
|
+
/**
|
|
32
|
+
* If the user provide some custom prompt for the image generation,
|
|
33
|
+
* we will use it, add the post content as additional context and
|
|
34
|
+
* provide some guardrails for the generation.
|
|
35
|
+
*/
|
|
36
|
+
if (userPrompt) {
|
|
37
|
+
const imageGenerationPrompt = `I need a cover image for a blog post based on this user prompt:
|
|
38
|
+
|
|
39
|
+
${userPrompt.length > 1000 ? userPrompt.substring(0, 1000) : userPrompt}
|
|
40
|
+
|
|
41
|
+
Before creating the image, identify the main topic of the user prompt and relate it to the post content.
|
|
42
|
+
Do not represent the whole content in one image, keep it simple and just represent one single idea.
|
|
43
|
+
Do not add details, detailed explanations or highlights from the content, just represent the main idea as if it was a photograph.
|
|
44
|
+
Do not use collages or compositions with multiple elements or scenes. Stick to one single scene. Do not compose unrealistic scenes.
|
|
45
|
+
If the content describes facts, objects or concepts from the real world, represent them on a realistic style and do not make unreal compositions.
|
|
46
|
+
If the content is more abstract, use a more abstract style to represent the main idea.
|
|
47
|
+
Make sure the light and the style are visually appealing.
|
|
48
|
+
Do not add text to the image.
|
|
49
|
+
|
|
50
|
+
For additional context, this is the post content:
|
|
51
|
+
|
|
52
|
+
`;
|
|
53
|
+
// truncating the content so the whole prompt is not longer than 4000 characters, the model limit.
|
|
54
|
+
return imageGenerationPrompt + truncateContent(postContent, imageGenerationPrompt.length);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* When the user does not provide a custom prompt, we will use the
|
|
58
|
+
* standard one, based solely on the post content.
|
|
59
|
+
*/
|
|
60
|
+
const imageGenerationPrompt = `I need a cover image for a blog post.
|
|
24
61
|
Before creating the image, identify the main topic of the content and only represent it.
|
|
25
62
|
Do not represent the whole content in one image, keep it simple and just represent one single idea.
|
|
26
63
|
Do not add details, detailed explanations or highlights from the content, just represent the main idea as if it was a photograph.
|
|
@@ -32,7 +69,23 @@ Do not add text to the image.
|
|
|
32
69
|
|
|
33
70
|
This is the post content:
|
|
34
71
|
|
|
35
|
-
|
|
72
|
+
`;
|
|
73
|
+
// truncating the content so the whole prompt is not longer than 4000 characters, the model limit.
|
|
74
|
+
return imageGenerationPrompt + truncateContent(postContent, imageGenerationPrompt.length);
|
|
75
|
+
};
|
|
76
|
+
const useImageGenerator = () => {
|
|
77
|
+
const generateImage = async function ({ feature, postContent, responseFormat = 'url', userPrompt, }) {
|
|
78
|
+
let token = '';
|
|
79
|
+
try {
|
|
80
|
+
token = (await requestJwt()).token;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
debug('Error getting token: %o', error);
|
|
84
|
+
return Promise.reject(error);
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
debug('Generating image');
|
|
88
|
+
const imageGenerationPrompt = getImageGenerationPrompt(postContent, userPrompt);
|
|
36
89
|
const URL = 'https://public-api.wordpress.com/wpcom/v2/jetpack-ai-image';
|
|
37
90
|
const body = {
|
|
38
91
|
prompt: imageGenerationPrompt,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"private": false,
|
|
3
3
|
"name": "@automattic/jetpack-ai-client",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.13.0",
|
|
5
5
|
"description": "A JS client for consuming Jetpack AI services",
|
|
6
6
|
"homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/ai-client/#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
},
|
|
24
24
|
"type": "module",
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@storybook/addon-actions": "8.0.
|
|
27
|
-
"@storybook/blocks": "8.0.
|
|
28
|
-
"@storybook/preview-api": "8.0.
|
|
29
|
-
"@storybook/react": "8.0.
|
|
30
|
-
"@types/markdown-it": "14.0.
|
|
26
|
+
"@storybook/addon-actions": "8.0.9",
|
|
27
|
+
"@storybook/blocks": "8.0.9",
|
|
28
|
+
"@storybook/preview-api": "8.0.9",
|
|
29
|
+
"@storybook/react": "8.0.9",
|
|
30
|
+
"@types/markdown-it": "14.0.1",
|
|
31
31
|
"@types/turndown": "5.0.4",
|
|
32
32
|
"jest": "^29.6.2",
|
|
33
33
|
"jest-environment-jsdom": "29.7.0",
|
|
@@ -42,19 +42,19 @@
|
|
|
42
42
|
"main": "./build/index.js",
|
|
43
43
|
"types": "./build/index.d.ts",
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@automattic/jetpack-base-styles": "^0.6.
|
|
46
|
-
"@automattic/jetpack-connection": "^0.33.
|
|
47
|
-
"@automattic/jetpack-shared-extension-utils": "^0.14.
|
|
45
|
+
"@automattic/jetpack-base-styles": "^0.6.24",
|
|
46
|
+
"@automattic/jetpack-connection": "^0.33.9",
|
|
47
|
+
"@automattic/jetpack-shared-extension-utils": "^0.14.11",
|
|
48
48
|
"@microsoft/fetch-event-source": "2.0.1",
|
|
49
|
-
"@types/react": "18.
|
|
50
|
-
"@wordpress/api-fetch": "6.
|
|
51
|
-
"@wordpress/block-editor": "12.
|
|
52
|
-
"@wordpress/components": "27.
|
|
53
|
-
"@wordpress/compose": "6.
|
|
54
|
-
"@wordpress/data": "9.
|
|
55
|
-
"@wordpress/element": "5.
|
|
56
|
-
"@wordpress/i18n": "4.
|
|
57
|
-
"@wordpress/icons": "9.
|
|
49
|
+
"@types/react": "18.3.1",
|
|
50
|
+
"@wordpress/api-fetch": "6.53.0",
|
|
51
|
+
"@wordpress/block-editor": "12.24.0",
|
|
52
|
+
"@wordpress/components": "27.4.0",
|
|
53
|
+
"@wordpress/compose": "6.33.0",
|
|
54
|
+
"@wordpress/data": "9.26.0",
|
|
55
|
+
"@wordpress/element": "5.33.0",
|
|
56
|
+
"@wordpress/i18n": "4.56.0",
|
|
57
|
+
"@wordpress/icons": "9.47.0",
|
|
58
58
|
"classnames": "2.3.2",
|
|
59
59
|
"debug": "4.3.4",
|
|
60
60
|
"markdown-it": "14.0.0",
|
|
@@ -27,6 +27,7 @@ type AIControlProps = {
|
|
|
27
27
|
actions?: ReactElement;
|
|
28
28
|
message?: ReactElement;
|
|
29
29
|
promptUserInputRef?: React.MutableRefObject< HTMLInputElement >;
|
|
30
|
+
wrapperRef?: React.MutableRefObject< HTMLDivElement | null >;
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -47,9 +48,10 @@ export default function AIControl( {
|
|
|
47
48
|
actions = null,
|
|
48
49
|
message = null,
|
|
49
50
|
promptUserInputRef = null,
|
|
51
|
+
wrapperRef = null,
|
|
50
52
|
}: AIControlProps ): ReactElement {
|
|
51
53
|
return (
|
|
52
|
-
<div className="jetpack-components-ai-control__container-wrapper">
|
|
54
|
+
<div className="jetpack-components-ai-control__container-wrapper" ref={ wrapperRef }>
|
|
53
55
|
{ error }
|
|
54
56
|
<div className="jetpack-components-ai-control__container">
|
|
55
57
|
{ banner }
|
|
@@ -30,6 +30,7 @@ type ExtensionAIControlProps = {
|
|
|
30
30
|
error?: string;
|
|
31
31
|
requestsRemaining?: number;
|
|
32
32
|
showUpgradeMessage?: boolean;
|
|
33
|
+
wrapperRef?: React.MutableRefObject< HTMLDivElement | null >;
|
|
33
34
|
onChange?: ( newValue: string ) => void;
|
|
34
35
|
onSend?: ( currentValue: string ) => void;
|
|
35
36
|
onStop?: () => void;
|
|
@@ -57,6 +58,7 @@ export function ExtensionAIControl(
|
|
|
57
58
|
error,
|
|
58
59
|
requestsRemaining,
|
|
59
60
|
showUpgradeMessage = false,
|
|
61
|
+
wrapperRef,
|
|
60
62
|
onChange,
|
|
61
63
|
onSend,
|
|
62
64
|
onStop,
|
|
@@ -210,6 +212,7 @@ export function ExtensionAIControl(
|
|
|
210
212
|
actions={ actions }
|
|
211
213
|
message={ message }
|
|
212
214
|
promptUserInputRef={ promptUserInputRef }
|
|
215
|
+
wrapperRef={ wrapperRef }
|
|
213
216
|
/>
|
|
214
217
|
);
|
|
215
218
|
}
|
|
@@ -9,15 +9,86 @@ import requestJwt from '../../jwt/index.js';
|
|
|
9
9
|
|
|
10
10
|
const debug = debugFactory( 'ai-client:use-image-generator' );
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Cut the post content on a given lenght so the total length of the prompt is not longer than 4000 characters.
|
|
14
|
+
* @param {string} content - the content to be truncated
|
|
15
|
+
* @param {number} currentPromptLength - the length of the prompt already in use
|
|
16
|
+
* @returns {string} a truncated version of the content respecting the prompt length limit
|
|
17
|
+
*/
|
|
18
|
+
const truncateContent = ( content: string, currentPromptLength: number ): string => {
|
|
19
|
+
const maxLength = 4000;
|
|
20
|
+
const remainingLength = maxLength - currentPromptLength;
|
|
21
|
+
// 6 is the length of the ellipsis and the space before it
|
|
22
|
+
return content.length > remainingLength
|
|
23
|
+
? content.substring( 0, remainingLength - 6 ) + ` [...]`
|
|
24
|
+
: content;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create the prompt string based on the provided context.
|
|
29
|
+
* @param {string} postContent - the content of the post
|
|
30
|
+
* @param {string} userPrompt - the user prompt for the image generation, if provided. Max length is 1000 characters, will be truncated.
|
|
31
|
+
* @returns {string} the prompt string
|
|
32
|
+
*/
|
|
33
|
+
const getImageGenerationPrompt = ( postContent: string, userPrompt?: string ): string => {
|
|
34
|
+
/**
|
|
35
|
+
* If the user provide some custom prompt for the image generation,
|
|
36
|
+
* we will use it, add the post content as additional context and
|
|
37
|
+
* provide some guardrails for the generation.
|
|
38
|
+
*/
|
|
39
|
+
if ( userPrompt ) {
|
|
40
|
+
const imageGenerationPrompt = `I need a cover image for a blog post based on this user prompt:
|
|
41
|
+
|
|
42
|
+
${ userPrompt.length > 1000 ? userPrompt.substring( 0, 1000 ) : userPrompt }
|
|
43
|
+
|
|
44
|
+
Before creating the image, identify the main topic of the user prompt and relate it to the post content.
|
|
45
|
+
Do not represent the whole content in one image, keep it simple and just represent one single idea.
|
|
46
|
+
Do not add details, detailed explanations or highlights from the content, just represent the main idea as if it was a photograph.
|
|
47
|
+
Do not use collages or compositions with multiple elements or scenes. Stick to one single scene. Do not compose unrealistic scenes.
|
|
48
|
+
If the content describes facts, objects or concepts from the real world, represent them on a realistic style and do not make unreal compositions.
|
|
49
|
+
If the content is more abstract, use a more abstract style to represent the main idea.
|
|
50
|
+
Make sure the light and the style are visually appealing.
|
|
51
|
+
Do not add text to the image.
|
|
52
|
+
|
|
53
|
+
For additional context, this is the post content:
|
|
54
|
+
|
|
55
|
+
`;
|
|
56
|
+
// truncating the content so the whole prompt is not longer than 4000 characters, the model limit.
|
|
57
|
+
return imageGenerationPrompt + truncateContent( postContent, imageGenerationPrompt.length );
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* When the user does not provide a custom prompt, we will use the
|
|
62
|
+
* standard one, based solely on the post content.
|
|
63
|
+
*/
|
|
64
|
+
const imageGenerationPrompt = `I need a cover image for a blog post.
|
|
65
|
+
Before creating the image, identify the main topic of the content and only represent it.
|
|
66
|
+
Do not represent the whole content in one image, keep it simple and just represent one single idea.
|
|
67
|
+
Do not add details, detailed explanations or highlights from the content, just represent the main idea as if it was a photograph.
|
|
68
|
+
Do not use collages or compositions with multiple elements or scenes. Stick to one single scene. Do not compose unrealistic scenes.
|
|
69
|
+
If the content describes facts, objects or concepts from the real world, represent them on a realistic style and do not make unreal compositions.
|
|
70
|
+
If the content is more abstract, use a more abstract style to represent the main idea.
|
|
71
|
+
Make sure the light and the style are visually appealing.
|
|
72
|
+
Do not add text to the image.
|
|
73
|
+
|
|
74
|
+
This is the post content:
|
|
75
|
+
|
|
76
|
+
`;
|
|
77
|
+
// truncating the content so the whole prompt is not longer than 4000 characters, the model limit.
|
|
78
|
+
return imageGenerationPrompt + truncateContent( postContent, imageGenerationPrompt.length );
|
|
79
|
+
};
|
|
80
|
+
|
|
12
81
|
const useImageGenerator = () => {
|
|
13
82
|
const generateImage = async function ( {
|
|
14
83
|
feature,
|
|
15
84
|
postContent,
|
|
16
85
|
responseFormat = 'url',
|
|
86
|
+
userPrompt,
|
|
17
87
|
}: {
|
|
18
88
|
feature: string;
|
|
19
89
|
postContent: string;
|
|
20
90
|
responseFormat?: 'url' | 'b64_json';
|
|
91
|
+
userPrompt?: string;
|
|
21
92
|
} ): Promise< { data: Array< { [ key: string ]: string } > } > {
|
|
22
93
|
let token = '';
|
|
23
94
|
|
|
@@ -31,21 +102,7 @@ const useImageGenerator = () => {
|
|
|
31
102
|
try {
|
|
32
103
|
debug( 'Generating image' );
|
|
33
104
|
|
|
34
|
-
|
|
35
|
-
const imageGenerationPrompt =
|
|
36
|
-
`I need a cover image for a blog post.
|
|
37
|
-
Before creating the image, identify the main topic of the content and only represent it.
|
|
38
|
-
Do not represent the whole content in one image, keep it simple and just represent one single idea.
|
|
39
|
-
Do not add details, detailed explanations or highlights from the content, just represent the main idea as if it was a photograph.
|
|
40
|
-
Do not use collages or compositions with multiple elements or scenes. Stick to one single scene. Do not compose unrealistic scenes.
|
|
41
|
-
If the content describes facts, objects or concepts from the real world, represent them on a realistic style and do not make unreal compositions.
|
|
42
|
-
If the content is more abstract, use a more abstract style to represent the main idea.
|
|
43
|
-
Make sure the light and the style are visually appealing.
|
|
44
|
-
Do not add text to the image.
|
|
45
|
-
|
|
46
|
-
This is the post content:
|
|
47
|
-
|
|
48
|
-
` + ( postContent.length > 3000 ? postContent.substring( 0, 3000 ) + ` [...]` : postContent ); // truncating the content so the whole prompt is not longer than 4000 characters, the model limit.
|
|
105
|
+
const imageGenerationPrompt = getImageGenerationPrompt( postContent, userPrompt );
|
|
49
106
|
|
|
50
107
|
const URL = 'https://public-api.wordpress.com/wpcom/v2/jetpack-ai-image';
|
|
51
108
|
|