@automattic/jetpack-ai-client 0.25.3 → 0.25.5

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 (28) hide show
  1. package/CHANGELOG.md +18 -1
  2. package/build/ai-client/src/components/ai-control/block-ai-control.d.ts +2 -1
  3. package/build/ai-client/src/components/ai-control/block-ai-control.js +10 -2
  4. package/build/ai-client/src/components/ai-control/extension-ai-control.d.ts +3 -1
  5. package/build/ai-client/src/components/ai-control/extension-ai-control.js +9 -3
  6. package/build/ai-client/src/components/ai-feedback/index.d.ts +1 -0
  7. package/build/ai-client/src/components/ai-feedback/index.js +3 -2
  8. package/build/ai-client/src/components/message/index.d.ts +15 -4
  9. package/build/ai-client/src/components/message/index.js +22 -5
  10. package/build/ai-client/src/constants.d.ts +106 -0
  11. package/build/ai-client/src/constants.js +113 -0
  12. package/build/ai-client/src/index.d.ts +1 -0
  13. package/build/ai-client/src/index.js +4 -0
  14. package/build/ai-client/src/libs/index.d.ts +1 -0
  15. package/build/ai-client/src/libs/index.js +1 -0
  16. package/build/ai-client/src/libs/map-action-to-human-text.d.ts +13 -0
  17. package/build/ai-client/src/libs/map-action-to-human-text.js +40 -0
  18. package/build/ai-client/src/logo-generator/components/generator-modal.js +1 -1
  19. package/package.json +12 -12
  20. package/src/components/ai-control/block-ai-control.tsx +15 -1
  21. package/src/components/ai-control/extension-ai-control.tsx +18 -2
  22. package/src/components/ai-feedback/index.tsx +4 -2
  23. package/src/components/message/index.tsx +45 -12
  24. package/src/constants.ts +116 -0
  25. package/src/index.ts +5 -0
  26. package/src/libs/index.ts +2 -0
  27. package/src/libs/map-action-to-human-text.ts +77 -0
  28. package/src/logo-generator/components/generator-modal.tsx +1 -1
package/CHANGELOG.md CHANGED
@@ -5,9 +5,24 @@ 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.25.5] - 2025-01-06
9
+ ### Changed
10
+ - Updated package dependencies. [#40798] [#40810] [#40811] [#40841]
11
+
12
+ ### Fixed
13
+ - AI Client: Add style parameter to first logo generator so it doesn't fall in a DALL-E situation. [#40807]
14
+ - Jetpack AI: Switch tracking data to camel_case to maintain Tracks' required property format. [#40774]
15
+
16
+ ## [0.25.4] - 2024-12-30
17
+ ### Added
18
+ - AI Client: Add thumbs feedback on AI Assistant. [#40728]
19
+
20
+ ### Changed
21
+ - AI Client: Move prompt types and update thumbs feedback event. [#40746]
22
+
8
23
  ## [0.25.3] - 2024-12-23
9
24
  ### Added
10
- - Jetpack AI: Add thumbs up/down component to AI logo generator [#40610]
25
+ - Jetpack AI: Add thumbs up/down component to AI logo generator. [#40610]
11
26
 
12
27
  ## [0.25.2] - 2024-12-16
13
28
  ### Changed
@@ -487,6 +502,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
487
502
  - AI Client: stop using smart document visibility handling on the fetchEventSource library, so it does not restart the completion when changing tabs. [#32004]
488
503
  - Updated package dependencies. [#31468] [#31659] [#31785]
489
504
 
505
+ [0.25.5]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.4...v0.25.5
506
+ [0.25.4]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.3...v0.25.4
490
507
  [0.25.3]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.2...v0.25.3
491
508
  [0.25.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.1...v0.25.2
492
509
  [0.25.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.0...v0.25.1
@@ -24,6 +24,7 @@ type BlockAIControlProps = {
24
24
  showRemove?: boolean;
25
25
  banner?: ReactElement;
26
26
  error?: ReactElement;
27
+ lastAction?: string;
27
28
  };
28
29
  /**
29
30
  * BlockAIControl component. Used by the AI Assistant block, adding logic and components to the base AIControl component.
@@ -32,6 +33,6 @@ type BlockAIControlProps = {
32
33
  * @param {React.MutableRefObject} ref - Ref to the component
33
34
  * @return {ReactElement} Rendered component
34
35
  */
35
- export declare function BlockAIControl({ disabled, value, placeholder, showAccept, acceptLabel, showButtonLabels, isTransparent, state, showGuideLine, customFooter, onChange, onSend, onStop, onAccept, onDiscard, showRemove, banner, error, }: BlockAIControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
36
+ export declare function BlockAIControl({ disabled, value, placeholder, showAccept, acceptLabel, showButtonLabels, isTransparent, state, showGuideLine, customFooter, onChange, onSend, onStop, onAccept, onDiscard, showRemove, banner, error, lastAction, }: BlockAIControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
36
37
  declare const _default: React.ForwardRefExoticComponent<BlockAIControlProps & React.RefAttributes<HTMLInputElement>>;
37
38
  export default _default;
@@ -23,7 +23,7 @@ const debug = debugFactory('jetpack-ai-client:block-ai-control');
23
23
  * @param {React.MutableRefObject} ref - Ref to the component
24
24
  * @return {ReactElement} Rendered component
25
25
  */
26
- export function BlockAIControl({ disabled = false, value = '', placeholder = '', showAccept = false, acceptLabel = __('Accept', 'jetpack-ai-client'), showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, customFooter = null, onChange, onSend, onStop, onAccept, onDiscard, showRemove = false, banner = null, error = null, }, ref) {
26
+ export function BlockAIControl({ disabled = false, value = '', placeholder = '', showAccept = false, acceptLabel = __('Accept', 'jetpack-ai-client'), showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, customFooter = null, onChange, onSend, onStop, onAccept, onDiscard, showRemove = false, banner = null, error = null, lastAction, }, ref) {
27
27
  const loading = state === 'requesting' || state === 'suggesting';
28
28
  const [editRequest, setEditRequest] = useState(false);
29
29
  const [lastValue, setLastValue] = useState(value || null);
@@ -76,7 +76,15 @@ export function BlockAIControl({ disabled = false, value = '', placeholder = '',
76
76
  target: promptUserInputRef,
77
77
  });
78
78
  const actions = (_jsxs(_Fragment, { children: [(!showAccept || editRequest) && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: !loading ? (_jsxs(_Fragment, { children: [editRequest && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: cancelEdit, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), showRemove && !editRequest && !value?.length && onDiscard && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: discardHandler, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), value?.length > 0 && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendHandler, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }))] })) : (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onStop, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Stop', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })) })), showAccept && !editRequest && (_jsxs("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: [(value?.length > 0 || lastValue === null) && (_jsxs(ButtonGroup, { children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Discard', 'jetpack-ai-client'), onClick: discardHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: trash }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Regenerate', 'jetpack-ai-client'), onClick: () => onSend?.(value), tooltipPosition: "top", disabled: !value?.length || value === null || disabled, children: _jsx(Icon, { icon: regenerate }) })] })), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onAccept, variant: "primary", label: acceptLabel, children: showButtonLabels ? acceptLabel : _jsx(Icon, { icon: check }) })] }))] }));
79
- const message = showGuideLine && !loading && !editRequest && (customFooter || _jsx(GuidelineMessage, {}));
79
+ const message = showGuideLine &&
80
+ !loading &&
81
+ !editRequest &&
82
+ (customFooter || (_jsx(GuidelineMessage, { aiFeedbackThumbsOptions: {
83
+ showAIFeedbackThumbs: true,
84
+ ratedItem: 'ai-assistant',
85
+ prompt: lastAction,
86
+ block: 'ai-assistant',
87
+ } })));
80
88
  return (_jsx(AIControl, { disabled: disabled || loading, value: value, placeholder: placeholder, isTransparent: isTransparent, state: state, onChange: changeHandler, banner: banner, error: error, actions: actions, message: message, promptUserInputRef: promptUserInputRef }));
81
89
  }
82
90
  export default forwardRef(BlockAIControl);
@@ -27,6 +27,8 @@ type ExtensionAIControlProps = {
27
27
  onUndo?: () => void;
28
28
  onUpgrade?: (event: MouseEvent<HTMLButtonElement>) => void;
29
29
  onTryAgain?: () => void;
30
+ lastAction?: string;
31
+ blockType: string;
30
32
  };
31
33
  /**
32
34
  * ExtensionAIControl component. Used by the AI Assistant inline extensions, adding logic and components to the base AIControl component.
@@ -35,6 +37,6 @@ type ExtensionAIControlProps = {
35
37
  * @param {React.MutableRefObject} ref - Ref to the component
36
38
  * @return {ReactElement} Rendered component
37
39
  */
38
- export declare function ExtensionAIControl({ className, disabled, value, placeholder, showButtonLabels, isTransparent, state, showGuideLine, error, requestsRemaining, showUpgradeMessage, showFairUsageMessage, upgradeUrl, wrapperRef, onChange, onSend, onStop, onClose, onUndo, onUpgrade, onTryAgain, }: ExtensionAIControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
40
+ export declare function ExtensionAIControl({ className, disabled, value, placeholder, showButtonLabels, isTransparent, state, showGuideLine, error, requestsRemaining, showUpgradeMessage, showFairUsageMessage, upgradeUrl, wrapperRef, onChange, onSend, onStop, onClose, onUndo, onUpgrade, onTryAgain, lastAction, blockType, }: ExtensionAIControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
39
41
  declare const _default: React.ForwardRefExoticComponent<ExtensionAIControlProps & React.RefAttributes<HTMLInputElement>>;
40
42
  export default _default;
@@ -21,11 +21,12 @@ import './style.scss';
21
21
  * @param {React.MutableRefObject} ref - Ref to the component
22
22
  * @return {ReactElement} Rendered component
23
23
  */
24
- export function ExtensionAIControl({ className, disabled = false, value = '', placeholder = '', showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, error, requestsRemaining, showUpgradeMessage = false, showFairUsageMessage = false, upgradeUrl, wrapperRef, onChange, onSend, onStop, onClose, onUndo, onUpgrade, onTryAgain, }, ref) {
24
+ export function ExtensionAIControl({ className, disabled = false, value = '', placeholder = '', showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, error, requestsRemaining, showUpgradeMessage = false, showFairUsageMessage = false, upgradeUrl, wrapperRef, onChange, onSend, onStop, onClose, onUndo, onUpgrade, onTryAgain, lastAction, blockType, }, ref) {
25
25
  const loading = state === 'requesting' || state === 'suggesting';
26
26
  const [editRequest, setEditRequest] = useState(false);
27
27
  const [lastValue, setLastValue] = useState(value || null);
28
28
  const promptUserInputRef = useRef(null);
29
+ const isDone = value?.length <= 0 && state === 'done';
29
30
  // Pass the ref to forwardRef.
30
31
  useImperativeHandle(ref, () => promptUserInputRef.current);
31
32
  useEffect(() => {
@@ -73,7 +74,7 @@ export function ExtensionAIControl({ className, disabled = false, value = '', pl
73
74
  }, {
74
75
  target: promptUserInputRef,
75
76
  });
76
- const actions = (_jsx(_Fragment, { children: loading ? (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: stopHandler, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? __('Stop', 'jetpack-ai-client') : _jsx(Icon, { icon: closeSmall }) })) : (_jsxs(_Fragment, { children: [value?.length > 0 && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendHandler, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }) })), value?.length <= 0 && state === 'done' && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsxs(ButtonGroup, { children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Undo', 'jetpack-ai-client'), onClick: undoHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: undo }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Close', 'jetpack-ai-client'), onClick: closeHandler, variant: "tertiary", children: __('Close', 'jetpack-ai-client') })] }) }))] })) }));
77
+ const actions = (_jsx(_Fragment, { children: loading ? (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: stopHandler, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? __('Stop', 'jetpack-ai-client') : _jsx(Icon, { icon: closeSmall }) })) : (_jsxs(_Fragment, { children: [value?.length > 0 && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendHandler, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }) })), isDone && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsxs(ButtonGroup, { children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Undo', 'jetpack-ai-client'), onClick: undoHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: undo }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Close', 'jetpack-ai-client'), onClick: closeHandler, variant: "tertiary", children: __('Close', 'jetpack-ai-client') })] }) }))] })) }));
77
78
  let message = null;
78
79
  if (error?.message) {
79
80
  message = (_jsx(ErrorMessage, { error: error.message, code: error.code, onTryAgainClick: tryAgainHandler, onUpgradeClick: upgradeHandler, upgradeUrl: upgradeUrl }));
@@ -85,7 +86,12 @@ export function ExtensionAIControl({ className, disabled = false, value = '', pl
85
86
  message = (_jsx(UpgradeMessage, { requestsRemaining: requestsRemaining, onUpgradeClick: upgradeHandler, upgradeUrl: upgradeUrl }));
86
87
  }
87
88
  else if (showGuideLine) {
88
- message = _jsx(GuidelineMessage, {});
89
+ message = isDone ? (_jsx(GuidelineMessage, { aiFeedbackThumbsOptions: {
90
+ showAIFeedbackThumbs: true,
91
+ ratedItem: 'ai-assistant',
92
+ prompt: lastAction,
93
+ block: blockType,
94
+ } })) : (_jsx(GuidelineMessage, {}));
89
95
  }
90
96
  return (_jsx(AIControl, { className: className, disabled: disabled || loading, value: value, placeholder: placeholder, isTransparent: isTransparent, state: state, onChange: changeHandler, actions: actions, message: message, promptUserInputRef: promptUserInputRef, wrapperRef: wrapperRef }));
91
97
  }
@@ -13,6 +13,7 @@ type AiFeedbackThumbsProps = {
13
13
  mediaLibraryId?: number;
14
14
  prompt?: string;
15
15
  revisedPrompt?: string;
16
+ block?: string | null;
16
17
  };
17
18
  onRate?: (rating: string) => void;
18
19
  };
@@ -56,9 +56,10 @@ export default function AiFeedbackThumbs({ disabled = false, iconSize = 24, rate
56
56
  tracks.recordEvent('jetpack_ai_feedback', {
57
57
  type: feature,
58
58
  rating: aiRating,
59
- mediaLibraryId: options.mediaLibraryId || null,
59
+ media_library_id: options.mediaLibraryId || null,
60
60
  prompt: options.prompt || null,
61
- revisedPrompt: options.revisedPrompt || null,
61
+ revised_prompt: options.revisedPrompt || null,
62
+ block: options.block || null,
62
63
  });
63
64
  }
64
65
  };
@@ -12,13 +12,22 @@ export declare const MESSAGE_SEVERITY_ERROR = "error";
12
12
  export declare const MESSAGE_SEVERITY_SUCCESS = "success";
13
13
  export declare const MESSAGE_SEVERITY_INFO = "info";
14
14
  export type MessageSeverityProp = typeof MESSAGE_SEVERITY_WARNING | typeof MESSAGE_SEVERITY_ERROR | typeof MESSAGE_SEVERITY_SUCCESS | typeof MESSAGE_SEVERITY_INFO | null;
15
+ type AiFeedbackThumbsOptions = {
16
+ showAIFeedbackThumbs?: boolean;
17
+ ratedItem?: string;
18
+ prompt?: string;
19
+ block?: string | null;
20
+ onRate?: (rating: string) => void;
21
+ };
15
22
  export type MessageProps = {
16
23
  icon?: React.ReactNode;
17
24
  severity?: MessageSeverityProp;
18
- showSidebarIcon?: boolean;
19
- onSidebarIconClick?: () => void;
25
+ aiFeedbackThumbsOptions?: AiFeedbackThumbsOptions;
20
26
  children: React.ReactNode;
21
27
  };
28
+ export type GuidelineMessageProps = {
29
+ aiFeedbackThumbsOptions?: AiFeedbackThumbsOptions;
30
+ };
22
31
  export type OnUpgradeClick = (event?: React.MouseEvent<HTMLButtonElement>) => void;
23
32
  export type UpgradeMessageProps = {
24
33
  requestsRemaining: number;
@@ -39,13 +48,14 @@ export type ErrorMessageProps = {
39
48
  * @param {MessageProps} props - Component props.
40
49
  * @return {React.ReactElement} Banner component.
41
50
  */
42
- export default function Message({ severity, icon, showSidebarIcon, onSidebarIconClick, children, }: MessageProps): React.ReactElement;
51
+ export default function Message({ severity, icon, aiFeedbackThumbsOptions, children, }: MessageProps): React.ReactElement;
43
52
  /**
44
53
  * React component to render a guideline message.
45
54
  *
55
+ * @param {GuidelineMessageProps} props - Component props.
46
56
  * @return {React.ReactElement} - Message component.
47
57
  */
48
- export declare function GuidelineMessage(): React.ReactElement;
58
+ export declare function GuidelineMessage({ aiFeedbackThumbsOptions, }: GuidelineMessageProps): React.ReactElement;
49
59
  /**
50
60
  * React component to render a fair usage limit message.
51
61
  *
@@ -66,3 +76,4 @@ export declare function UpgradeMessage({ requestsRemaining, severity, onUpgradeC
66
76
  * @return {React.ReactElement} - Message component.
67
77
  */
68
78
  export declare function ErrorMessage({ error, code, onTryAgainClick, onUpgradeClick, upgradeUrl, }: ErrorMessageProps): React.ReactElement;
79
+ export {};
@@ -5,7 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
5
  import { ExternalLink, Button } from '@wordpress/components';
6
6
  import { createInterpolateElement } from '@wordpress/element';
7
7
  import { __, sprintf } from '@wordpress/i18n';
8
- import { Icon, check, arrowRight } from '@wordpress/icons';
8
+ import { Icon, check } from '@wordpress/icons';
9
9
  import clsx from 'clsx';
10
10
  /**
11
11
  * Internal dependencies
@@ -13,6 +13,7 @@ import clsx from 'clsx';
13
13
  import './style.scss';
14
14
  import errorExclamation from '../../icons/error-exclamation.js';
15
15
  import { ERROR_QUOTA_EXCEEDED } from '../../types.js';
16
+ import AiFeedbackThumbs from '../ai-feedback/index.js';
16
17
  export const MESSAGE_SEVERITY_WARNING = 'warning';
17
18
  export const MESSAGE_SEVERITY_ERROR = 'error';
18
19
  export const MESSAGE_SEVERITY_SUCCESS = 'success';
@@ -29,8 +30,17 @@ const messageIconsMap = {
29
30
  * @param {MessageProps} props - Component props.
30
31
  * @return {React.ReactElement} Banner component.
31
32
  */
32
- export default function Message({ severity = MESSAGE_SEVERITY_INFO, icon = null, showSidebarIcon = false, onSidebarIconClick = () => { }, children, }) {
33
- return (_jsxs("div", { className: clsx('jetpack-ai-assistant__message', `jetpack-ai-assistant__message-severity-${severity}`), children: [(messageIconsMap[severity] || icon) && (_jsx(Icon, { icon: messageIconsMap[severity] || icon })), _jsx("div", { className: "jetpack-ai-assistant__message-content", children: children }), showSidebarIcon && (_jsx(Button, { className: "jetpack-ai-assistant__message-sidebar", onClick: onSidebarIconClick, children: _jsx(Icon, { size: 20, icon: arrowRight }) }))] }));
33
+ export default function Message({ severity = MESSAGE_SEVERITY_INFO, icon = null, aiFeedbackThumbsOptions = {
34
+ showAIFeedbackThumbs: false,
35
+ ratedItem: '',
36
+ prompt: '',
37
+ block: null,
38
+ onRate: () => { },
39
+ }, children, }) {
40
+ return (_jsxs("div", { className: clsx('jetpack-ai-assistant__message', `jetpack-ai-assistant__message-severity-${severity}`), children: [(messageIconsMap[severity] || icon) && (_jsx(Icon, { icon: messageIconsMap[severity] || icon })), _jsx("div", { className: "jetpack-ai-assistant__message-content", children: children }), aiFeedbackThumbsOptions.showAIFeedbackThumbs && aiFeedbackThumbsOptions.prompt && (_jsx(AiFeedbackThumbs, { disabled: false, ratedItem: aiFeedbackThumbsOptions.ratedItem, feature: "ai-assistant", options: {
41
+ prompt: aiFeedbackThumbsOptions.prompt,
42
+ block: aiFeedbackThumbsOptions.block,
43
+ }, onRate: aiFeedbackThumbsOptions.onRate }))] }));
34
44
  }
35
45
  /**
36
46
  * React component to render a learn more link.
@@ -43,10 +53,17 @@ function LearnMoreLink() {
43
53
  /**
44
54
  * React component to render a guideline message.
45
55
  *
56
+ * @param {GuidelineMessageProps} props - Component props.
46
57
  * @return {React.ReactElement} - Message component.
47
58
  */
48
- export function GuidelineMessage() {
49
- return (_jsxs(Message, { children: [_jsx("span", { children: __('AI-generated content could be inaccurate or biased.', 'jetpack-ai-client') }), _jsx(LearnMoreLink, {})] }));
59
+ export function GuidelineMessage({ aiFeedbackThumbsOptions = {
60
+ showAIFeedbackThumbs: false,
61
+ ratedItem: '',
62
+ prompt: '',
63
+ block: null,
64
+ onRate: () => { },
65
+ }, }) {
66
+ return (_jsxs(Message, { aiFeedbackThumbsOptions: aiFeedbackThumbsOptions, children: [_jsx("span", { children: __('AI-generated content could be inaccurate or biased.', 'jetpack-ai-client') }), _jsx(LearnMoreLink, {})] }));
50
67
  }
51
68
  /**
52
69
  * React component to render a fair usage limit message.
@@ -0,0 +1,106 @@
1
+ export declare const LANGUAGE_MAP: {
2
+ en: {
3
+ label: string;
4
+ };
5
+ es: {
6
+ label: string;
7
+ };
8
+ fr: {
9
+ label: string;
10
+ };
11
+ de: {
12
+ label: string;
13
+ };
14
+ it: {
15
+ label: string;
16
+ };
17
+ pt: {
18
+ label: string;
19
+ };
20
+ ru: {
21
+ label: string;
22
+ };
23
+ zh: {
24
+ label: string;
25
+ };
26
+ ja: {
27
+ label: string;
28
+ };
29
+ ar: {
30
+ label: string;
31
+ };
32
+ hi: {
33
+ label: string;
34
+ };
35
+ ko: {
36
+ label: string;
37
+ };
38
+ };
39
+ export declare const PROMPT_TONES_MAP: {
40
+ formal: {
41
+ label: string;
42
+ emoji: string;
43
+ };
44
+ informal: {
45
+ label: string;
46
+ emoji: string;
47
+ };
48
+ optimistic: {
49
+ label: string;
50
+ emoji: string;
51
+ };
52
+ humorous: {
53
+ label: string;
54
+ emoji: string;
55
+ };
56
+ serious: {
57
+ label: string;
58
+ emoji: string;
59
+ };
60
+ skeptical: {
61
+ label: string;
62
+ emoji: string;
63
+ };
64
+ empathetic: {
65
+ label: string;
66
+ emoji: string;
67
+ };
68
+ confident: {
69
+ label: string;
70
+ emoji: string;
71
+ };
72
+ passionate: {
73
+ label: string;
74
+ emoji: string;
75
+ };
76
+ provocative: {
77
+ label: string;
78
+ emoji: string;
79
+ };
80
+ };
81
+ export declare const PROMPT_TYPE_SUMMARY_BY_TITLE: "titleSummary";
82
+ export declare const PROMPT_TYPE_CONTINUE: "continue";
83
+ export declare const PROMPT_TYPE_SIMPLIFY: "simplify";
84
+ export declare const PROMPT_TYPE_CORRECT_SPELLING: "correctSpelling";
85
+ export declare const PROMPT_TYPE_GENERATE_TITLE: "generateTitle";
86
+ export declare const PROMPT_TYPE_MAKE_LONGER: "makeLonger";
87
+ export declare const PROMPT_TYPE_MAKE_SHORTER: "makeShorter";
88
+ export declare const PROMPT_TYPE_CHANGE_TONE: "changeTone";
89
+ export declare const PROMPT_TYPE_SUMMARIZE: "summarize";
90
+ export declare const PROMPT_TYPE_CHANGE_LANGUAGE: "changeLanguage";
91
+ export declare const PROMPT_TYPE_USER_PROMPT: "userPrompt";
92
+ export declare const PROMPT_TYPE_JETPACK_FORM_CUSTOM_PROMPT: "jetpackFormCustomPrompt";
93
+ export declare const PROMPT_TYPE_TRANSFORM_LIST_TO_TABLE: "transformListToTable";
94
+ export declare const PROMPT_TYPE_WRITE_POST_FROM_LIST: "writePostFromList";
95
+ export declare const TRANSLATE_LABEL: string;
96
+ export declare const TONE_LABEL: string;
97
+ export declare const CORRECT_SPELLING_LABEL: string;
98
+ export declare const SIMPLIFY_LABEL: string;
99
+ export declare const SUMMARIZE_LABEL: string;
100
+ export declare const MAKE_SHORTER_LABEL: string;
101
+ export declare const MAKE_LONGER_LABEL: string;
102
+ export declare const TURN_LIST_INTO_TABLE_LABEL: string;
103
+ export declare const WRITE_POST_FROM_LIST_LABEL: string;
104
+ export declare const GENERATE_TITLE_LABEL: string;
105
+ export declare const SUMMARY_BASED_ON_TITLE_LABEL: string;
106
+ export declare const CONTINUE_LABEL: string;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ // Mappings
6
+ export const LANGUAGE_MAP = {
7
+ en: {
8
+ label: __('English', 'jetpack-ai-client'),
9
+ },
10
+ es: {
11
+ label: __('Spanish', 'jetpack-ai-client'),
12
+ },
13
+ fr: {
14
+ label: __('French', 'jetpack-ai-client'),
15
+ },
16
+ de: {
17
+ label: __('German', 'jetpack-ai-client'),
18
+ },
19
+ it: {
20
+ label: __('Italian', 'jetpack-ai-client'),
21
+ },
22
+ pt: {
23
+ label: __('Portuguese', 'jetpack-ai-client'),
24
+ },
25
+ ru: {
26
+ label: __('Russian', 'jetpack-ai-client'),
27
+ },
28
+ zh: {
29
+ label: __('Chinese', 'jetpack-ai-client'),
30
+ },
31
+ ja: {
32
+ label: __('Japanese', 'jetpack-ai-client'),
33
+ },
34
+ ar: {
35
+ label: __('Arabic', 'jetpack-ai-client'),
36
+ },
37
+ hi: {
38
+ label: __('Hindi', 'jetpack-ai-client'),
39
+ },
40
+ ko: {
41
+ label: __('Korean', 'jetpack-ai-client'),
42
+ },
43
+ };
44
+ export const PROMPT_TONES_MAP = {
45
+ formal: {
46
+ label: __('Formal', 'jetpack-ai-client'),
47
+ emoji: '🎩',
48
+ },
49
+ informal: {
50
+ label: __('Informal', 'jetpack-ai-client'),
51
+ emoji: '😊',
52
+ },
53
+ optimistic: {
54
+ label: __('Optimistic', 'jetpack-ai-client'),
55
+ emoji: '😃',
56
+ },
57
+ humorous: {
58
+ label: __('Humorous', 'jetpack-ai-client'),
59
+ emoji: '😂',
60
+ },
61
+ serious: {
62
+ label: __('Serious', 'jetpack-ai-client'),
63
+ emoji: '😐',
64
+ },
65
+ skeptical: {
66
+ label: __('Skeptical', 'jetpack-ai-client'),
67
+ emoji: '🤨',
68
+ },
69
+ empathetic: {
70
+ label: __('Empathetic', 'jetpack-ai-client'),
71
+ emoji: '💗',
72
+ },
73
+ confident: {
74
+ label: __('Confident', 'jetpack-ai-client'),
75
+ emoji: '😎',
76
+ },
77
+ passionate: {
78
+ label: __('Passionate', 'jetpack-ai-client'),
79
+ emoji: '❤️',
80
+ },
81
+ provocative: {
82
+ label: __('Provocative', 'jetpack-ai-client'),
83
+ emoji: '🔥',
84
+ },
85
+ };
86
+ // Prompt types
87
+ export const PROMPT_TYPE_SUMMARY_BY_TITLE = 'titleSummary';
88
+ export const PROMPT_TYPE_CONTINUE = 'continue';
89
+ export const PROMPT_TYPE_SIMPLIFY = 'simplify';
90
+ export const PROMPT_TYPE_CORRECT_SPELLING = 'correctSpelling';
91
+ export const PROMPT_TYPE_GENERATE_TITLE = 'generateTitle';
92
+ export const PROMPT_TYPE_MAKE_LONGER = 'makeLonger';
93
+ export const PROMPT_TYPE_MAKE_SHORTER = 'makeShorter';
94
+ export const PROMPT_TYPE_CHANGE_TONE = 'changeTone';
95
+ export const PROMPT_TYPE_SUMMARIZE = 'summarize';
96
+ export const PROMPT_TYPE_CHANGE_LANGUAGE = 'changeLanguage';
97
+ export const PROMPT_TYPE_USER_PROMPT = 'userPrompt';
98
+ export const PROMPT_TYPE_JETPACK_FORM_CUSTOM_PROMPT = 'jetpackFormCustomPrompt';
99
+ export const PROMPT_TYPE_TRANSFORM_LIST_TO_TABLE = 'transformListToTable';
100
+ export const PROMPT_TYPE_WRITE_POST_FROM_LIST = 'writePostFromList';
101
+ // Human-readable labels
102
+ export const TRANSLATE_LABEL = __('Translate', 'jetpack-ai-client');
103
+ export const TONE_LABEL = __('Change tone', 'jetpack-ai-client');
104
+ export const CORRECT_SPELLING_LABEL = __('Correct spelling and grammar', 'jetpack-ai-client');
105
+ export const SIMPLIFY_LABEL = __('Simplify', 'jetpack-ai-client');
106
+ export const SUMMARIZE_LABEL = __('Summarize', 'jetpack-ai-client');
107
+ export const MAKE_SHORTER_LABEL = __('Make shorter', 'jetpack-ai-client');
108
+ export const MAKE_LONGER_LABEL = __('Expand', 'jetpack-ai-client');
109
+ export const TURN_LIST_INTO_TABLE_LABEL = __('Turn list into a table', 'jetpack-ai-client');
110
+ export const WRITE_POST_FROM_LIST_LABEL = __('Write a post from this list', 'jetpack-ai-client');
111
+ export const GENERATE_TITLE_LABEL = __('Generate a post title', 'jetpack-ai-client');
112
+ export const SUMMARY_BASED_ON_TITLE_LABEL = __('Summary based on title', 'jetpack-ai-client');
113
+ export const CONTINUE_LABEL = __('Continue writing', 'jetpack-ai-client');
@@ -15,4 +15,5 @@ export * from './components/index.js';
15
15
  export * from './data-flow/index.js';
16
16
  export * from './types.js';
17
17
  export * from './libs/index.js';
18
+ export * from './constants.js';
18
19
  export * from './logo-generator/index.js';
@@ -36,6 +36,10 @@ export * from './types.js';
36
36
  * Libs
37
37
  */
38
38
  export * from './libs/index.js';
39
+ /*
40
+ * Constants
41
+ */
42
+ export * from './constants.js';
39
43
  /*
40
44
  * Logo Generator
41
45
  */
@@ -1,2 +1,3 @@
1
1
  export { MarkdownToHTML, HTMLToMarkdown, renderHTMLFromMarkdown, renderMarkdownFromHTML, fixes, } from './markdown/index.js';
2
2
  export type { RenderHTMLRules } from './markdown/index.js';
3
+ export { mapActionToHumanText } from './map-action-to-human-text.js';
@@ -1 +1,2 @@
1
1
  export { MarkdownToHTML, HTMLToMarkdown, renderHTMLFromMarkdown, renderMarkdownFromHTML, fixes, } from './markdown/index.js';
2
+ export { mapActionToHumanText } from './map-action-to-human-text.js';
@@ -0,0 +1,13 @@
1
+ type MapActionToHumanTextOptions = {
2
+ language?: string;
3
+ tone?: string;
4
+ };
5
+ /**
6
+ * Maps an action to a human-readable text.
7
+ *
8
+ * @param action - The action to map.
9
+ * @param options - The options for the mapping.
10
+ * @return {string} The human-readable text.
11
+ */
12
+ export declare function mapActionToHumanText(action: string, options?: MapActionToHumanTextOptions): string | null;
13
+ export {};
@@ -0,0 +1,40 @@
1
+ import { LANGUAGE_MAP, PROMPT_TONES_MAP, PROMPT_TYPE_CHANGE_LANGUAGE, PROMPT_TYPE_CHANGE_TONE, PROMPT_TYPE_CONTINUE, PROMPT_TYPE_CORRECT_SPELLING, PROMPT_TYPE_GENERATE_TITLE, PROMPT_TYPE_MAKE_LONGER, PROMPT_TYPE_MAKE_SHORTER, PROMPT_TYPE_SIMPLIFY, PROMPT_TYPE_SUMMARIZE, PROMPT_TYPE_SUMMARY_BY_TITLE, PROMPT_TYPE_TRANSFORM_LIST_TO_TABLE, PROMPT_TYPE_WRITE_POST_FROM_LIST, CONTINUE_LABEL, CORRECT_SPELLING_LABEL, GENERATE_TITLE_LABEL, MAKE_LONGER_LABEL, MAKE_SHORTER_LABEL, SIMPLIFY_LABEL, SUMMARIZE_LABEL, SUMMARY_BASED_ON_TITLE_LABEL, TONE_LABEL, TRANSLATE_LABEL, TURN_LIST_INTO_TABLE_LABEL, WRITE_POST_FROM_LIST_LABEL, } from '../constants.js';
2
+ /**
3
+ * Maps an action to a human-readable text.
4
+ *
5
+ * @param action - The action to map.
6
+ * @param options - The options for the mapping.
7
+ * @return {string} The human-readable text.
8
+ */
9
+ export function mapActionToHumanText(action, options = {}) {
10
+ const { language, tone } = options;
11
+ const languageCode = language?.split(' (')[0];
12
+ switch (action) {
13
+ case PROMPT_TYPE_CHANGE_LANGUAGE:
14
+ return `${TRANSLATE_LABEL}: ${LANGUAGE_MAP[languageCode].label}`;
15
+ case PROMPT_TYPE_CHANGE_TONE:
16
+ return `${TONE_LABEL}: ${PROMPT_TONES_MAP[tone].label}`;
17
+ case PROMPT_TYPE_CORRECT_SPELLING:
18
+ return CORRECT_SPELLING_LABEL;
19
+ case PROMPT_TYPE_SIMPLIFY:
20
+ return SIMPLIFY_LABEL;
21
+ case PROMPT_TYPE_SUMMARIZE:
22
+ return SUMMARIZE_LABEL;
23
+ case PROMPT_TYPE_MAKE_LONGER:
24
+ return MAKE_LONGER_LABEL;
25
+ case PROMPT_TYPE_MAKE_SHORTER:
26
+ return MAKE_SHORTER_LABEL;
27
+ case PROMPT_TYPE_TRANSFORM_LIST_TO_TABLE:
28
+ return TURN_LIST_INTO_TABLE_LABEL;
29
+ case PROMPT_TYPE_WRITE_POST_FROM_LIST:
30
+ return WRITE_POST_FROM_LIST_LABEL;
31
+ case PROMPT_TYPE_GENERATE_TITLE:
32
+ return GENERATE_TITLE_LABEL;
33
+ case PROMPT_TYPE_SUMMARY_BY_TITLE:
34
+ return SUMMARY_BASED_ON_TITLE_LABEL;
35
+ case PROMPT_TYPE_CONTINUE:
36
+ return CONTINUE_LABEL;
37
+ default:
38
+ return null;
39
+ }
40
+ }
@@ -55,7 +55,7 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload = null,
55
55
  setInitialPrompt(prompt);
56
56
  // Then generate the logo based on the prompt.
57
57
  setLoadingState('generating');
58
- await generateLogo({ prompt });
58
+ await generateLogo({ prompt, style: 'none' });
59
59
  setLoadingState(null);
60
60
  }
61
61
  catch (error) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@automattic/jetpack-ai-client",
4
- "version": "0.25.3",
4
+ "version": "0.25.5",
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": {
@@ -24,15 +24,15 @@
24
24
  },
25
25
  "type": "module",
26
26
  "devDependencies": {
27
- "@storybook/addon-actions": "8.3.5",
28
- "@storybook/blocks": "8.3.5",
29
- "@storybook/preview-api": "8.3.5",
30
- "@storybook/react": "8.3.5",
27
+ "@storybook/addon-actions": "8.4.7",
28
+ "@storybook/blocks": "8.4.7",
29
+ "@storybook/preview-api": "8.4.7",
30
+ "@storybook/react": "8.4.7",
31
31
  "@types/markdown-it": "14.1.2",
32
32
  "@types/turndown": "5.0.5",
33
33
  "jest": "^29.6.2",
34
34
  "jest-environment-jsdom": "29.7.0",
35
- "storybook": "8.3.5",
35
+ "storybook": "8.4.7",
36
36
  "typescript": "5.0.4"
37
37
  },
38
38
  "exports": {
@@ -45,11 +45,11 @@
45
45
  "types": "./build/index.d.ts",
46
46
  "dependencies": {
47
47
  "@automattic/jetpack-base-styles": "^0.6.39",
48
- "@automattic/jetpack-connection": "^0.36.2",
49
- "@automattic/jetpack-shared-extension-utils": "^0.16.2",
48
+ "@automattic/jetpack-connection": "^0.36.3",
49
+ "@automattic/jetpack-shared-extension-utils": "^0.16.3",
50
50
  "@microsoft/fetch-event-source": "2.0.1",
51
- "@types/react": "18.3.12",
52
- "@types/wordpress__block-editor": "11.5.15",
51
+ "@types/react": "18.3.18",
52
+ "@types/wordpress__block-editor": "11.5.16",
53
53
  "@wordpress/api-fetch": "7.14.0",
54
54
  "@wordpress/base-styles": "5.14.0",
55
55
  "@wordpress/blob": "4.14.0",
@@ -61,8 +61,8 @@
61
61
  "@wordpress/i18n": "5.14.0",
62
62
  "@wordpress/icons": "10.14.0",
63
63
  "clsx": "2.1.1",
64
- "debug": "4.3.4",
65
- "markdown-it": "14.0.0",
64
+ "debug": "4.4.0",
65
+ "markdown-it": "14.1.0",
66
66
  "react": "18.3.1",
67
67
  "react-dom": "18.3.1",
68
68
  "turndown": "7.1.2"
@@ -46,6 +46,7 @@ type BlockAIControlProps = {
46
46
  showRemove?: boolean;
47
47
  banner?: ReactElement;
48
48
  error?: ReactElement;
49
+ lastAction?: string;
49
50
  };
50
51
 
51
52
  const debug = debugFactory( 'jetpack-ai-client:block-ai-control' );
@@ -77,6 +78,7 @@ export function BlockAIControl(
77
78
  showRemove = false,
78
79
  banner = null,
79
80
  error = null,
81
+ lastAction,
80
82
  }: BlockAIControlProps,
81
83
  ref: React.MutableRefObject< HTMLInputElement >
82
84
  ): ReactElement {
@@ -256,7 +258,19 @@ export function BlockAIControl(
256
258
  );
257
259
 
258
260
  const message =
259
- showGuideLine && ! loading && ! editRequest && ( customFooter || <GuidelineMessage /> );
261
+ showGuideLine &&
262
+ ! loading &&
263
+ ! editRequest &&
264
+ ( customFooter || (
265
+ <GuidelineMessage
266
+ aiFeedbackThumbsOptions={ {
267
+ showAIFeedbackThumbs: true,
268
+ ratedItem: 'ai-assistant',
269
+ prompt: lastAction,
270
+ block: 'ai-assistant',
271
+ } }
272
+ />
273
+ ) );
260
274
 
261
275
  return (
262
276
  <AIControl
@@ -46,6 +46,8 @@ type ExtensionAIControlProps = {
46
46
  onUndo?: () => void;
47
47
  onUpgrade?: ( event: MouseEvent< HTMLButtonElement > ) => void;
48
48
  onTryAgain?: () => void;
49
+ lastAction?: string;
50
+ blockType: string;
49
51
  };
50
52
 
51
53
  /**
@@ -78,6 +80,8 @@ export function ExtensionAIControl(
78
80
  onUndo,
79
81
  onUpgrade,
80
82
  onTryAgain,
83
+ lastAction,
84
+ blockType,
81
85
  }: ExtensionAIControlProps,
82
86
  ref: React.MutableRefObject< HTMLInputElement >
83
87
  ): ReactElement {
@@ -85,6 +89,7 @@ export function ExtensionAIControl(
85
89
  const [ editRequest, setEditRequest ] = useState( false );
86
90
  const [ lastValue, setLastValue ] = useState( value || null );
87
91
  const promptUserInputRef = useRef( null );
92
+ const isDone = value?.length <= 0 && state === 'done';
88
93
 
89
94
  // Pass the ref to forwardRef.
90
95
  useImperativeHandle( ref, () => promptUserInputRef.current );
@@ -183,7 +188,7 @@ export function ExtensionAIControl(
183
188
  </Button>
184
189
  </div>
185
190
  ) }
186
- { value?.length <= 0 && state === 'done' && (
191
+ { isDone && (
187
192
  <div className="jetpack-components-ai-control__controls-prompt_button_wrapper">
188
193
  <ButtonGroup>
189
194
  <Button
@@ -233,7 +238,18 @@ export function ExtensionAIControl(
233
238
  />
234
239
  );
235
240
  } else if ( showGuideLine ) {
236
- message = <GuidelineMessage />;
241
+ message = isDone ? (
242
+ <GuidelineMessage
243
+ aiFeedbackThumbsOptions={ {
244
+ showAIFeedbackThumbs: true,
245
+ ratedItem: 'ai-assistant',
246
+ prompt: lastAction,
247
+ block: blockType,
248
+ } }
249
+ />
250
+ ) : (
251
+ <GuidelineMessage />
252
+ );
237
253
  }
238
254
 
239
255
  return (
@@ -29,6 +29,7 @@ type AiFeedbackThumbsProps = {
29
29
  mediaLibraryId?: number;
30
30
  prompt?: string;
31
31
  revisedPrompt?: string;
32
+ block?: string | null;
32
33
  };
33
34
  onRate?: ( rating: string ) => void;
34
35
  };
@@ -95,9 +96,10 @@ export default function AiFeedbackThumbs( {
95
96
  tracks.recordEvent( 'jetpack_ai_feedback', {
96
97
  type: feature,
97
98
  rating: aiRating,
98
- mediaLibraryId: options.mediaLibraryId || null,
99
+ media_library_id: options.mediaLibraryId || null,
99
100
  prompt: options.prompt || null,
100
- revisedPrompt: options.revisedPrompt || null,
101
+ revised_prompt: options.revisedPrompt || null,
102
+ block: options.block || null,
101
103
  } );
102
104
  }
103
105
  };
@@ -4,7 +4,7 @@
4
4
  import { ExternalLink, Button } from '@wordpress/components';
5
5
  import { createInterpolateElement } from '@wordpress/element';
6
6
  import { __, sprintf } from '@wordpress/i18n';
7
- import { Icon, check, arrowRight } from '@wordpress/icons';
7
+ import { Icon, check } from '@wordpress/icons';
8
8
  import clsx from 'clsx';
9
9
  /**
10
10
  * Internal dependencies
@@ -12,6 +12,7 @@ import clsx from 'clsx';
12
12
  import './style.scss';
13
13
  import errorExclamation from '../../icons/error-exclamation.js';
14
14
  import { ERROR_QUOTA_EXCEEDED } from '../../types.js';
15
+ import AiFeedbackThumbs from '../ai-feedback/index.js';
15
16
  /**
16
17
  * Types
17
18
  */
@@ -30,14 +31,25 @@ export type MessageSeverityProp =
30
31
  | typeof MESSAGE_SEVERITY_INFO
31
32
  | null;
32
33
 
34
+ type AiFeedbackThumbsOptions = {
35
+ showAIFeedbackThumbs?: boolean;
36
+ ratedItem?: string;
37
+ prompt?: string;
38
+ block?: string | null;
39
+ onRate?: ( rating: string ) => void;
40
+ };
41
+
33
42
  export type MessageProps = {
34
43
  icon?: React.ReactNode;
35
44
  severity?: MessageSeverityProp;
36
- showSidebarIcon?: boolean;
37
- onSidebarIconClick?: () => void;
45
+ aiFeedbackThumbsOptions?: AiFeedbackThumbsOptions;
38
46
  children: React.ReactNode;
39
47
  };
40
48
 
49
+ export type GuidelineMessageProps = {
50
+ aiFeedbackThumbsOptions?: AiFeedbackThumbsOptions;
51
+ };
52
+
41
53
  export type OnUpgradeClick = ( event?: React.MouseEvent< HTMLButtonElement > ) => void;
42
54
 
43
55
  export type UpgradeMessageProps = {
@@ -71,8 +83,13 @@ const messageIconsMap = {
71
83
  export default function Message( {
72
84
  severity = MESSAGE_SEVERITY_INFO,
73
85
  icon = null,
74
- showSidebarIcon = false,
75
- onSidebarIconClick = () => {},
86
+ aiFeedbackThumbsOptions = {
87
+ showAIFeedbackThumbs: false,
88
+ ratedItem: '',
89
+ prompt: '',
90
+ block: null,
91
+ onRate: () => {},
92
+ },
76
93
  children,
77
94
  }: MessageProps ): React.ReactElement {
78
95
  return (
@@ -85,11 +102,18 @@ export default function Message( {
85
102
  { ( messageIconsMap[ severity ] || icon ) && (
86
103
  <Icon icon={ messageIconsMap[ severity ] || icon } />
87
104
  ) }
88
- <div className="jetpack-ai-assistant__message-content">{ children }</div>
89
- { showSidebarIcon && (
90
- <Button className="jetpack-ai-assistant__message-sidebar" onClick={ onSidebarIconClick }>
91
- <Icon size={ 20 } icon={ arrowRight } />
92
- </Button>
105
+ { <div className="jetpack-ai-assistant__message-content">{ children }</div> }
106
+ { aiFeedbackThumbsOptions.showAIFeedbackThumbs && aiFeedbackThumbsOptions.prompt && (
107
+ <AiFeedbackThumbs
108
+ disabled={ false }
109
+ ratedItem={ aiFeedbackThumbsOptions.ratedItem }
110
+ feature="ai-assistant"
111
+ options={ {
112
+ prompt: aiFeedbackThumbsOptions.prompt,
113
+ block: aiFeedbackThumbsOptions.block,
114
+ } }
115
+ onRate={ aiFeedbackThumbsOptions.onRate }
116
+ />
93
117
  ) }
94
118
  </div>
95
119
  );
@@ -111,11 +135,20 @@ function LearnMoreLink(): React.ReactElement {
111
135
  /**
112
136
  * React component to render a guideline message.
113
137
  *
138
+ * @param {GuidelineMessageProps} props - Component props.
114
139
  * @return {React.ReactElement} - Message component.
115
140
  */
116
- export function GuidelineMessage(): React.ReactElement {
141
+ export function GuidelineMessage( {
142
+ aiFeedbackThumbsOptions = {
143
+ showAIFeedbackThumbs: false,
144
+ ratedItem: '',
145
+ prompt: '',
146
+ block: null,
147
+ onRate: () => {},
148
+ },
149
+ }: GuidelineMessageProps ): React.ReactElement {
117
150
  return (
118
- <Message>
151
+ <Message aiFeedbackThumbsOptions={ aiFeedbackThumbsOptions }>
119
152
  <span>
120
153
  { __( 'AI-generated content could be inaccurate or biased.', 'jetpack-ai-client' ) }
121
154
  </span>
@@ -0,0 +1,116 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ // Mappings
7
+ export const LANGUAGE_MAP = {
8
+ en: {
9
+ label: __( 'English', 'jetpack-ai-client' ),
10
+ },
11
+ es: {
12
+ label: __( 'Spanish', 'jetpack-ai-client' ),
13
+ },
14
+ fr: {
15
+ label: __( 'French', 'jetpack-ai-client' ),
16
+ },
17
+ de: {
18
+ label: __( 'German', 'jetpack-ai-client' ),
19
+ },
20
+ it: {
21
+ label: __( 'Italian', 'jetpack-ai-client' ),
22
+ },
23
+ pt: {
24
+ label: __( 'Portuguese', 'jetpack-ai-client' ),
25
+ },
26
+ ru: {
27
+ label: __( 'Russian', 'jetpack-ai-client' ),
28
+ },
29
+ zh: {
30
+ label: __( 'Chinese', 'jetpack-ai-client' ),
31
+ },
32
+ ja: {
33
+ label: __( 'Japanese', 'jetpack-ai-client' ),
34
+ },
35
+ ar: {
36
+ label: __( 'Arabic', 'jetpack-ai-client' ),
37
+ },
38
+ hi: {
39
+ label: __( 'Hindi', 'jetpack-ai-client' ),
40
+ },
41
+ ko: {
42
+ label: __( 'Korean', 'jetpack-ai-client' ),
43
+ },
44
+ };
45
+ export const PROMPT_TONES_MAP = {
46
+ formal: {
47
+ label: __( 'Formal', 'jetpack-ai-client' ),
48
+ emoji: '🎩',
49
+ },
50
+ informal: {
51
+ label: __( 'Informal', 'jetpack-ai-client' ),
52
+ emoji: '😊',
53
+ },
54
+ optimistic: {
55
+ label: __( 'Optimistic', 'jetpack-ai-client' ),
56
+ emoji: '😃',
57
+ },
58
+ humorous: {
59
+ label: __( 'Humorous', 'jetpack-ai-client' ),
60
+ emoji: '😂',
61
+ },
62
+ serious: {
63
+ label: __( 'Serious', 'jetpack-ai-client' ),
64
+ emoji: '😐',
65
+ },
66
+ skeptical: {
67
+ label: __( 'Skeptical', 'jetpack-ai-client' ),
68
+ emoji: '🤨',
69
+ },
70
+ empathetic: {
71
+ label: __( 'Empathetic', 'jetpack-ai-client' ),
72
+ emoji: '💗',
73
+ },
74
+ confident: {
75
+ label: __( 'Confident', 'jetpack-ai-client' ),
76
+ emoji: '😎',
77
+ },
78
+ passionate: {
79
+ label: __( 'Passionate', 'jetpack-ai-client' ),
80
+ emoji: '❤️',
81
+ },
82
+ provocative: {
83
+ label: __( 'Provocative', 'jetpack-ai-client' ),
84
+ emoji: '🔥',
85
+ },
86
+ };
87
+
88
+ // Prompt types
89
+ export const PROMPT_TYPE_SUMMARY_BY_TITLE = 'titleSummary' as const;
90
+ export const PROMPT_TYPE_CONTINUE = 'continue' as const;
91
+ export const PROMPT_TYPE_SIMPLIFY = 'simplify' as const;
92
+ export const PROMPT_TYPE_CORRECT_SPELLING = 'correctSpelling' as const;
93
+ export const PROMPT_TYPE_GENERATE_TITLE = 'generateTitle' as const;
94
+ export const PROMPT_TYPE_MAKE_LONGER = 'makeLonger' as const;
95
+ export const PROMPT_TYPE_MAKE_SHORTER = 'makeShorter' as const;
96
+ export const PROMPT_TYPE_CHANGE_TONE = 'changeTone' as const;
97
+ export const PROMPT_TYPE_SUMMARIZE = 'summarize' as const;
98
+ export const PROMPT_TYPE_CHANGE_LANGUAGE = 'changeLanguage' as const;
99
+ export const PROMPT_TYPE_USER_PROMPT = 'userPrompt' as const;
100
+ export const PROMPT_TYPE_JETPACK_FORM_CUSTOM_PROMPT = 'jetpackFormCustomPrompt' as const;
101
+ export const PROMPT_TYPE_TRANSFORM_LIST_TO_TABLE = 'transformListToTable' as const;
102
+ export const PROMPT_TYPE_WRITE_POST_FROM_LIST = 'writePostFromList' as const;
103
+
104
+ // Human-readable labels
105
+ export const TRANSLATE_LABEL = __( 'Translate', 'jetpack-ai-client' );
106
+ export const TONE_LABEL = __( 'Change tone', 'jetpack-ai-client' );
107
+ export const CORRECT_SPELLING_LABEL = __( 'Correct spelling and grammar', 'jetpack-ai-client' );
108
+ export const SIMPLIFY_LABEL = __( 'Simplify', 'jetpack-ai-client' );
109
+ export const SUMMARIZE_LABEL = __( 'Summarize', 'jetpack-ai-client' );
110
+ export const MAKE_SHORTER_LABEL = __( 'Make shorter', 'jetpack-ai-client' );
111
+ export const MAKE_LONGER_LABEL = __( 'Expand', 'jetpack-ai-client' );
112
+ export const TURN_LIST_INTO_TABLE_LABEL = __( 'Turn list into a table', 'jetpack-ai-client' );
113
+ export const WRITE_POST_FROM_LIST_LABEL = __( 'Write a post from this list', 'jetpack-ai-client' );
114
+ export const GENERATE_TITLE_LABEL = __( 'Generate a post title', 'jetpack-ai-client' );
115
+ export const SUMMARY_BASED_ON_TITLE_LABEL = __( 'Summary based on title', 'jetpack-ai-client' );
116
+ export const CONTINUE_LABEL = __( 'Continue writing', 'jetpack-ai-client' );
package/src/index.ts CHANGED
@@ -43,6 +43,11 @@ export * from './types.js';
43
43
  */
44
44
  export * from './libs/index.js';
45
45
 
46
+ /*
47
+ * Constants
48
+ */
49
+ export * from './constants.js';
50
+
46
51
  /*
47
52
  * Logo Generator
48
53
  */
package/src/libs/index.ts CHANGED
@@ -7,3 +7,5 @@ export {
7
7
  } from './markdown/index.js';
8
8
 
9
9
  export type { RenderHTMLRules } from './markdown/index.js';
10
+
11
+ export { mapActionToHumanText } from './map-action-to-human-text.js';
@@ -0,0 +1,77 @@
1
+ import {
2
+ LANGUAGE_MAP,
3
+ PROMPT_TONES_MAP,
4
+ PROMPT_TYPE_CHANGE_LANGUAGE,
5
+ PROMPT_TYPE_CHANGE_TONE,
6
+ PROMPT_TYPE_CONTINUE,
7
+ PROMPT_TYPE_CORRECT_SPELLING,
8
+ PROMPT_TYPE_GENERATE_TITLE,
9
+ PROMPT_TYPE_MAKE_LONGER,
10
+ PROMPT_TYPE_MAKE_SHORTER,
11
+ PROMPT_TYPE_SIMPLIFY,
12
+ PROMPT_TYPE_SUMMARIZE,
13
+ PROMPT_TYPE_SUMMARY_BY_TITLE,
14
+ PROMPT_TYPE_TRANSFORM_LIST_TO_TABLE,
15
+ PROMPT_TYPE_WRITE_POST_FROM_LIST,
16
+ CONTINUE_LABEL,
17
+ CORRECT_SPELLING_LABEL,
18
+ GENERATE_TITLE_LABEL,
19
+ MAKE_LONGER_LABEL,
20
+ MAKE_SHORTER_LABEL,
21
+ SIMPLIFY_LABEL,
22
+ SUMMARIZE_LABEL,
23
+ SUMMARY_BASED_ON_TITLE_LABEL,
24
+ TONE_LABEL,
25
+ TRANSLATE_LABEL,
26
+ TURN_LIST_INTO_TABLE_LABEL,
27
+ WRITE_POST_FROM_LIST_LABEL,
28
+ } from '../constants.js';
29
+
30
+ type MapActionToHumanTextOptions = {
31
+ language?: string;
32
+ tone?: string;
33
+ };
34
+
35
+ /**
36
+ * Maps an action to a human-readable text.
37
+ *
38
+ * @param action - The action to map.
39
+ * @param options - The options for the mapping.
40
+ * @return {string} The human-readable text.
41
+ */
42
+ export function mapActionToHumanText(
43
+ action: string,
44
+ options: MapActionToHumanTextOptions = {}
45
+ ): string | null {
46
+ const { language, tone } = options;
47
+ const languageCode = language?.split( ' (' )[ 0 ];
48
+
49
+ switch ( action ) {
50
+ case PROMPT_TYPE_CHANGE_LANGUAGE:
51
+ return `${ TRANSLATE_LABEL }: ${ LANGUAGE_MAP[ languageCode ].label }`;
52
+ case PROMPT_TYPE_CHANGE_TONE:
53
+ return `${ TONE_LABEL }: ${ PROMPT_TONES_MAP[ tone ].label }`;
54
+ case PROMPT_TYPE_CORRECT_SPELLING:
55
+ return CORRECT_SPELLING_LABEL;
56
+ case PROMPT_TYPE_SIMPLIFY:
57
+ return SIMPLIFY_LABEL;
58
+ case PROMPT_TYPE_SUMMARIZE:
59
+ return SUMMARIZE_LABEL;
60
+ case PROMPT_TYPE_MAKE_LONGER:
61
+ return MAKE_LONGER_LABEL;
62
+ case PROMPT_TYPE_MAKE_SHORTER:
63
+ return MAKE_SHORTER_LABEL;
64
+ case PROMPT_TYPE_TRANSFORM_LIST_TO_TABLE:
65
+ return TURN_LIST_INTO_TABLE_LABEL;
66
+ case PROMPT_TYPE_WRITE_POST_FROM_LIST:
67
+ return WRITE_POST_FROM_LIST_LABEL;
68
+ case PROMPT_TYPE_GENERATE_TITLE:
69
+ return GENERATE_TITLE_LABEL;
70
+ case PROMPT_TYPE_SUMMARY_BY_TITLE:
71
+ return SUMMARY_BASED_ON_TITLE_LABEL;
72
+ case PROMPT_TYPE_CONTINUE:
73
+ return CONTINUE_LABEL;
74
+ default:
75
+ return null;
76
+ }
77
+ }
@@ -91,7 +91,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
91
91
 
92
92
  // Then generate the logo based on the prompt.
93
93
  setLoadingState( 'generating' );
94
- await generateLogo( { prompt } );
94
+ await generateLogo( { prompt, style: 'none' } );
95
95
  setLoadingState( null );
96
96
  } catch ( error ) {
97
97
  debug( 'Error generating first logo', error );