@automattic/jetpack-ai-client 0.1.15 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/build/ask-question/index.d.ts +32 -0
  3. package/build/ask-question/index.js +37 -0
  4. package/build/components/ai-control/index.d.ts +49 -0
  5. package/build/components/ai-control/index.js +53 -0
  6. package/build/components/ai-control/message.d.ts +30 -0
  7. package/build/components/ai-control/message.js +44 -0
  8. package/build/components/ai-status-indicator/index.d.ts +15 -0
  9. package/build/components/ai-status-indicator/index.js +22 -0
  10. package/build/components/audio-duration-display/index.d.ts +12 -0
  11. package/build/components/audio-duration-display/index.js +25 -0
  12. package/build/components/audio-duration-display/lib/media.d.ts +29 -0
  13. package/build/components/audio-duration-display/lib/media.js +52 -0
  14. package/build/components/index.d.ts +4 -0
  15. package/build/components/index.js +4 -0
  16. package/build/data-flow/context.d.ts +39 -0
  17. package/build/data-flow/context.js +22 -0
  18. package/build/data-flow/index.d.ts +3 -0
  19. package/build/data-flow/index.js +3 -0
  20. package/build/data-flow/use-ai-context.d.ts +24 -0
  21. package/build/data-flow/use-ai-context.js +46 -0
  22. package/build/data-flow/with-ai-assistant-data.d.ts +10 -0
  23. package/build/data-flow/with-ai-assistant-data.js +42 -0
  24. package/build/hooks/use-ai-suggestions/index.d.ts +48 -0
  25. package/build/hooks/use-ai-suggestions/index.js +214 -0
  26. package/build/hooks/use-media-recording/index.d.ts +42 -0
  27. package/build/hooks/use-media-recording/index.js +143 -0
  28. package/build/icons/ai-assistant.d.ts +2 -0
  29. package/build/icons/ai-assistant.js +7 -0
  30. package/build/icons/index.d.ts +7 -0
  31. package/build/icons/index.js +7 -0
  32. package/build/icons/mic.d.ts +2 -0
  33. package/build/icons/mic.js +7 -0
  34. package/build/icons/origami-plane.d.ts +2 -0
  35. package/build/icons/origami-plane.js +7 -0
  36. package/build/icons/player-pause.d.ts +2 -0
  37. package/build/icons/player-pause.js +7 -0
  38. package/build/icons/player-play.d.ts +2 -0
  39. package/build/icons/player-play.js +7 -0
  40. package/build/icons/player-stop.d.ts +2 -0
  41. package/build/icons/player-stop.js +7 -0
  42. package/build/icons/speak-tone.d.ts +2 -0
  43. package/build/icons/speak-tone.js +7 -0
  44. package/build/index.d.ts +9 -0
  45. package/build/index.js +27 -0
  46. package/build/jwt/index.d.ts +19 -0
  47. package/build/jwt/index.js +74 -0
  48. package/build/suggestions-event-source/index.d.ts +55 -0
  49. package/build/suggestions-event-source/index.js +282 -0
  50. package/build/types.d.ts +34 -0
  51. package/build/types.js +27 -0
  52. package/package.json +21 -14
  53. package/src/components/ai-control/index.tsx +21 -19
  54. package/src/data-flow/context.tsx +3 -3
  55. package/src/data-flow/with-ai-assistant-data.tsx +42 -39
  56. package/src/index.ts +32 -0
  57. package/src/types.ts +17 -0
  58. package/index.ts +0 -32
  59. package/src/global.d.ts +0 -9
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.2.0] - 2023-11-20
9
+ ### Changed
10
+ - Include built JavaScript code in addition to TypeScript. [#34118]
11
+
12
+ ## [0.1.16] - 2023-11-14
13
+ ### Changed
14
+ - Updated package dependencies. [#34093]
15
+
8
16
  ## [0.1.15] - 2023-11-13
9
17
  ### Changed
10
18
  - Prevented dispatching the `done` event for JETPACK_AI_ERROR. [#34051]
@@ -158,6 +166,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
158
166
  - Updated package dependencies. [#31659]
159
167
  - Updated package dependencies. [#31785]
160
168
 
169
+ [0.2.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.1.16...v0.2.0
170
+ [0.1.16]: https://github.com/Automattic/jetpack-ai-client/compare/v0.1.15...v0.1.16
161
171
  [0.1.15]: https://github.com/Automattic/jetpack-ai-client/compare/v0.1.14...v0.1.15
162
172
  [0.1.14]: https://github.com/Automattic/jetpack-ai-client/compare/v0.1.13...v0.1.14
163
173
  [0.1.13]: https://github.com/Automattic/jetpack-ai-client/compare/v0.1.12...v0.1.13
@@ -0,0 +1,32 @@
1
+ import SuggestionsEventSource from '../suggestions-event-source';
2
+ import type { AiModelTypeProp, PromptProp } from '../types';
3
+ export type AskQuestionOptionsArgProps = {
4
+ postId?: number;
5
+ fromCache?: boolean;
6
+ feature?: 'ai-assistant-experimental' | string | undefined;
7
+ model?: AiModelTypeProp;
8
+ functions?: Array<{
9
+ name?: string;
10
+ arguments?: string;
11
+ implementation?: Function;
12
+ }>;
13
+ };
14
+ /**
15
+ * An asynchronous function that asks a question
16
+ * and returns an event source with suggestions.
17
+ *
18
+ * @param {PromptProp} question - The question to ask. It can be a simple string or an array of PromptMessageItemProps objects.
19
+ * @param {AskQuestionOptionsArgProps} options - An optional object for additional configuration:
20
+ * @returns {Promise<SuggestionsEventSource>} A promise that resolves to an instance of the SuggestionsEventSource
21
+ * @example
22
+ * const question = "What is the meaning of life?";
23
+ * const options = {
24
+ * postId: 1,
25
+ * fromCache: true,
26
+ * feature: 'ai-assistant-experimental'
27
+ * }
28
+ * askQuestion( question, options ).then( suggestionsEventSource => {
29
+ * // handle suggestionsEventSource
30
+ * } );
31
+ */
32
+ export default function askQuestion(question: PromptProp, { postId, fromCache, feature, functions, model }?: AskQuestionOptionsArgProps): Promise<SuggestionsEventSource>;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import debugFactory from 'debug';
5
+ import SuggestionsEventSource from '../suggestions-event-source';
6
+ const debug = debugFactory('jetpack-ai-client:ask-question');
7
+ /**
8
+ * An asynchronous function that asks a question
9
+ * and returns an event source with suggestions.
10
+ *
11
+ * @param {PromptProp} question - The question to ask. It can be a simple string or an array of PromptMessageItemProps objects.
12
+ * @param {AskQuestionOptionsArgProps} options - An optional object for additional configuration:
13
+ * @returns {Promise<SuggestionsEventSource>} A promise that resolves to an instance of the SuggestionsEventSource
14
+ * @example
15
+ * const question = "What is the meaning of life?";
16
+ * const options = {
17
+ * postId: 1,
18
+ * fromCache: true,
19
+ * feature: 'ai-assistant-experimental'
20
+ * }
21
+ * askQuestion( question, options ).then( suggestionsEventSource => {
22
+ * // handle suggestionsEventSource
23
+ * } );
24
+ */
25
+ export default async function askQuestion(question, { postId = null, fromCache = false, feature, functions, model } = {}) {
26
+ debug('Asking question: %o. options: %o', question, {
27
+ postId,
28
+ fromCache,
29
+ feature,
30
+ functions,
31
+ model,
32
+ });
33
+ return new SuggestionsEventSource({
34
+ question,
35
+ options: { postId, feature, fromCache, functions, model },
36
+ });
37
+ }
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ /**
3
+ * Internal dependencies
4
+ */
5
+ import './style.scss';
6
+ /**
7
+ * Types
8
+ */
9
+ import type { RequestingStateProp } from '../../types';
10
+ /**
11
+ * AI Control component.
12
+ *
13
+ * @param {AIControlProps} props - Component props.
14
+ * @param {React.MutableRefObject} ref - Ref to the component.
15
+ * @returns {React.ReactElement} Rendered component.
16
+ */
17
+ export declare function AIControl({ disabled, value, placeholder, showAccept, acceptLabel, showButtonLabels, isTransparent, state, showClearButton, showGuideLine, onChange, onSend, onStop, onAccept, }: {
18
+ disabled?: boolean;
19
+ value: string;
20
+ placeholder?: string;
21
+ showAccept?: boolean;
22
+ acceptLabel?: string;
23
+ showButtonLabels?: boolean;
24
+ isTransparent?: boolean;
25
+ state?: RequestingStateProp;
26
+ showClearButton?: boolean;
27
+ showGuideLine?: boolean;
28
+ onChange?: (newValue: string) => void;
29
+ onSend?: (currentValue: string) => void;
30
+ onStop?: () => void;
31
+ onAccept?: () => void;
32
+ }, ref: React.MutableRefObject<null>): React.ReactElement;
33
+ declare const _default: React.ForwardRefExoticComponent<{
34
+ disabled?: boolean;
35
+ value: string;
36
+ placeholder?: string;
37
+ showAccept?: boolean;
38
+ acceptLabel?: string;
39
+ showButtonLabels?: boolean;
40
+ isTransparent?: boolean;
41
+ state?: "init" | "requesting" | "suggesting" | "done" | "error";
42
+ showClearButton?: boolean;
43
+ showGuideLine?: boolean;
44
+ onChange?: (newValue: string) => void;
45
+ onSend?: (currentValue: string) => void;
46
+ onStop?: () => void;
47
+ onAccept?: () => void;
48
+ } & React.RefAttributes<null>>;
49
+ export default _default;
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { PlainText } from '@wordpress/block-editor';
6
+ import { Button } from '@wordpress/components';
7
+ import { useKeyboardShortcut } from '@wordpress/compose';
8
+ import { forwardRef, useImperativeHandle, useRef } from '@wordpress/element';
9
+ import { __ } from '@wordpress/i18n';
10
+ import { Icon, closeSmall, check, arrowUp } from '@wordpress/icons';
11
+ import classNames from 'classnames';
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import './style.scss';
16
+ import AiStatusIndicator from '../ai-status-indicator';
17
+ import { GuidelineMessage } from './message';
18
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
19
+ const noop = () => { };
20
+ /**
21
+ * AI Control component.
22
+ *
23
+ * @param {AIControlProps} props - Component props.
24
+ * @param {React.MutableRefObject} ref - Ref to the component.
25
+ * @returns {React.ReactElement} Rendered component.
26
+ */
27
+ export function AIControl({ disabled = false, value = '', placeholder = '', showAccept = false, acceptLabel = __('Accept', 'jetpack-ai-client'), showButtonLabels = true, isTransparent = false, state = 'init', showClearButton = true, showGuideLine = false, onChange = noop, onSend = noop, onStop = noop, onAccept = noop, }, ref // eslint-disable-line @typescript-eslint/ban-types
28
+ ) {
29
+ const promptUserInputRef = useRef(null);
30
+ const loading = state === 'requesting' || state === 'suggesting';
31
+ // Pass the ref to forwardRef.
32
+ useImperativeHandle(ref, () => promptUserInputRef.current);
33
+ useKeyboardShortcut('mod+enter', () => {
34
+ if (showAccept) {
35
+ onAccept?.();
36
+ }
37
+ }, {
38
+ target: promptUserInputRef,
39
+ });
40
+ useKeyboardShortcut('enter', e => {
41
+ e.preventDefault();
42
+ onSend?.(value);
43
+ }, {
44
+ target: promptUserInputRef,
45
+ });
46
+ const actionButtonClasses = classNames('jetpack-components-ai-control__controls-prompt_button', {
47
+ 'has-label': showButtonLabels,
48
+ });
49
+ return (_jsxs("div", { className: "jetpack-components-ai-control__container", children: [_jsxs("div", { className: classNames('jetpack-components-ai-control__wrapper', {
50
+ 'is-transparent': isTransparent,
51
+ }), 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: loading || disabled, ref: promptUserInputRef }) }), value?.length > 0 && showClearButton && (_jsx(Button, { icon: closeSmall, className: "jetpack-components-ai-control__clear", onClick: () => onChange('') })), _jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: !loading ? (_jsxs(Button, { className: actionButtonClasses, onClick: () => onSend?.(value), isSmall: true, disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: [_jsx(Icon, { icon: arrowUp }), showButtonLabels && __('Send', 'jetpack-ai-client')] })) : (_jsxs(Button, { className: actionButtonClasses, onClick: onStop, isSmall: true, label: __('Stop request', 'jetpack-ai-client'), children: [_jsx(Icon, { icon: closeSmall }), showButtonLabels && __('Stop (ESC)', 'jetpack-ai-client')] })) }), showAccept && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsxs(Button, { className: actionButtonClasses, onClick: onAccept, isSmall: true, label: acceptLabel, children: [_jsx(Icon, { icon: check }), showButtonLabels && acceptLabel] }) }))] }), showGuideLine && _jsx(GuidelineMessage, {})] }));
52
+ }
53
+ export default forwardRef(AIControl);
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Types
3
+ */
4
+ import type React from 'react';
5
+ import './style.scss';
6
+ export declare const MESSAGE_SEVERITY_WARNING = "warning";
7
+ export declare const MESSAGE_SEVERITY_ERROR = "error";
8
+ export declare const MESSAGE_SEVERITY_SUCCESS = "success";
9
+ export declare const MESSAGE_SEVERITY_INFO = "info";
10
+ declare const messageSeverityTypes: readonly ["warning", "error", "success", "info"];
11
+ export type MessageSeverityProp = (typeof messageSeverityTypes)[number] | null;
12
+ export type MessageProps = {
13
+ icon?: React.ReactNode;
14
+ children: React.ReactNode;
15
+ severity: MessageSeverityProp;
16
+ };
17
+ /**
18
+ * React component to render a block message.
19
+ *
20
+ * @param {MessageProps} props - Component props.
21
+ * @returns {React.ReactElement } Banner component.
22
+ */
23
+ export default function Message({ severity, icon, children, }: MessageProps): React.ReactElement;
24
+ /**
25
+ * React component to render a guideline message.
26
+ *
27
+ * @returns {React.ReactElement } - Message component.
28
+ */
29
+ export declare function GuidelineMessage(): React.ReactElement;
30
+ export {};
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { ExternalLink } from '@wordpress/components';
6
+ import { createInterpolateElement } from '@wordpress/element';
7
+ import { __ } from '@wordpress/i18n';
8
+ import { Icon, warning, info, cancelCircleFilled as error, check as success, } from '@wordpress/icons';
9
+ import './style.scss';
10
+ export const MESSAGE_SEVERITY_WARNING = 'warning';
11
+ export const MESSAGE_SEVERITY_ERROR = 'error';
12
+ export const MESSAGE_SEVERITY_SUCCESS = 'success';
13
+ export const MESSAGE_SEVERITY_INFO = 'info';
14
+ const messageSeverityTypes = [
15
+ MESSAGE_SEVERITY_WARNING,
16
+ MESSAGE_SEVERITY_ERROR,
17
+ MESSAGE_SEVERITY_SUCCESS,
18
+ MESSAGE_SEVERITY_INFO,
19
+ ];
20
+ const messageIconsMap = {
21
+ [MESSAGE_SEVERITY_WARNING]: warning,
22
+ [MESSAGE_SEVERITY_ERROR]: error,
23
+ [MESSAGE_SEVERITY_SUCCESS]: success,
24
+ [MESSAGE_SEVERITY_INFO]: info,
25
+ };
26
+ /**
27
+ * React component to render a block message.
28
+ *
29
+ * @param {MessageProps} props - Component props.
30
+ * @returns {React.ReactElement } Banner component.
31
+ */
32
+ export default function Message({ severity = null, icon = null, children, }) {
33
+ return (_jsxs("div", { className: "jetpack-ai-assistant__message", children: [(severity || icon) && _jsx(Icon, { icon: messageIconsMap[severity] || icon }), _jsx("div", { className: "jetpack-ai-assistant__message-content", children: children })] }));
34
+ }
35
+ /**
36
+ * React component to render a guideline message.
37
+ *
38
+ * @returns {React.ReactElement } - Message component.
39
+ */
40
+ export function GuidelineMessage() {
41
+ return (_jsx(Message, { severity: MESSAGE_SEVERITY_INFO, children: createInterpolateElement(__('AI-generated content could be inaccurate or biased. <link>Learn more</link>', 'jetpack-ai-client'), {
42
+ link: _jsx(ExternalLink, { href: "https://automattic.com/ai-guidelines" }),
43
+ }) }));
44
+ }
@@ -0,0 +1,15 @@
1
+ import type { RequestingStateProp } from '../../types';
2
+ export type AiStatusIndicatorIconSize = 24 | 32 | 48 | 64;
3
+ import type React from 'react';
4
+ import './style.scss';
5
+ export type AiStatusIndicatorProps = {
6
+ state?: RequestingStateProp;
7
+ size?: AiStatusIndicatorIconSize;
8
+ };
9
+ /**
10
+ * AiStatusIndicator component.
11
+ *
12
+ * @param {AiStatusIndicatorProps} props - component props.
13
+ * @returns {React.ReactElement} - rendered component.
14
+ */
15
+ export default function AiStatusIndicator({ state, size, }: AiStatusIndicatorProps): React.ReactElement;
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { Icon } from '@wordpress/components';
6
+ import classNames from 'classnames';
7
+ /*
8
+ * Internal dependencies
9
+ */
10
+ import { aiAssistantIcon } from '../../icons';
11
+ import './style.scss';
12
+ /**
13
+ * AiStatusIndicator component.
14
+ *
15
+ * @param {AiStatusIndicatorProps} props - component props.
16
+ * @returns {React.ReactElement} - rendered component.
17
+ */
18
+ export default function AiStatusIndicator({ state, size = 24, }) {
19
+ return (_jsx("div", { className: classNames('jetpack-ai-status-indicator__icon-wrapper', {
20
+ [`is-${state}`]: true,
21
+ }), children: _jsx(Icon, { icon: aiAssistantIcon, size: size }) }));
22
+ }
@@ -0,0 +1,12 @@
1
+ import type React from 'react';
2
+ type AudioDurationDisplayProps = {
3
+ url: string;
4
+ };
5
+ /**
6
+ * AudioDurationDisplay component.
7
+ *
8
+ * @param {AudioDurationDisplayProps} props - Component props.
9
+ * @returns {React.ReactElement} Rendered component.
10
+ */
11
+ export default function AudioDurationDisplay({ url, }: AudioDurationDisplayProps): React.ReactElement;
12
+ export {};
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /*
3
+ * External dependencies
4
+ */
5
+ import { useState, useEffect } from '@wordpress/element';
6
+ /*
7
+ * Internal dependencies
8
+ */
9
+ import { formatTime, getDuration } from './lib/media';
10
+ /**
11
+ * AudioDurationDisplay component.
12
+ *
13
+ * @param {AudioDurationDisplayProps} props - Component props.
14
+ * @returns {React.ReactElement} Rendered component.
15
+ */
16
+ export default function AudioDurationDisplay({ url, }) {
17
+ const [duration, setDuration] = useState(0);
18
+ useEffect(() => {
19
+ if (!url) {
20
+ return;
21
+ }
22
+ getDuration(url).then(setDuration);
23
+ }, [url]);
24
+ return _jsx("span", { children: formatTime(duration, { addDecimalPart: false }) });
25
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Function to get duration of audio file
3
+ *
4
+ * @param {string} url - The url of the audio file
5
+ * @returns {Promise<number>} The duration of the audio file
6
+ * @see https://stackoverflow.com/questions/21522036/html-audio-tag-duration-always-infinity
7
+ */
8
+ export declare function getDuration(url: string): Promise<number>;
9
+ type FormatTimeOptions = {
10
+ /**
11
+ * Whether to add the decimal part to the formatted time.
12
+ *
13
+ */
14
+ addDecimalPart?: boolean;
15
+ };
16
+ /**
17
+ * Formats the given time in milliseconds into a string with the format HH:MM:SS.DD,
18
+ * adding hours and minutes only when needed.
19
+ *
20
+ * @param {number} time - The time in seconds to format.
21
+ * @param {FormatTimeOptions} options - The arguments.
22
+ * @returns {string} The formatted time string.
23
+ * @example
24
+ * const formattedTime1 = formatTime( 1234567 ); // Returns "20:34.56"
25
+ * const formattedTime2 = formatTime( 45123 ); // Returns "45.12"
26
+ * const formattedTime3 = formatTime( 64, { addDecimalPart: false } ); // Returns "01:04"
27
+ */
28
+ export declare function formatTime(time: number, { addDecimalPart }?: FormatTimeOptions): string;
29
+ export {};
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Function to get duration of audio file
3
+ *
4
+ * @param {string} url - The url of the audio file
5
+ * @returns {Promise<number>} The duration of the audio file
6
+ * @see https://stackoverflow.com/questions/21522036/html-audio-tag-duration-always-infinity
7
+ */
8
+ export function getDuration(url) {
9
+ return new Promise(next => {
10
+ const tmpAudioInstance = new Audio(url);
11
+ tmpAudioInstance.addEventListener('durationchange', function () {
12
+ if (this.duration === Infinity) {
13
+ return;
14
+ }
15
+ const duration = this.duration;
16
+ tmpAudioInstance.remove(); // remove instance from memory
17
+ next(duration);
18
+ }, false);
19
+ tmpAudioInstance.load();
20
+ tmpAudioInstance.currentTime = 24 * 60 * 60; // Fake big time
21
+ tmpAudioInstance.volume = 0;
22
+ tmpAudioInstance.play(); // This will call `durationchange` event
23
+ });
24
+ }
25
+ /**
26
+ * Formats the given time in milliseconds into a string with the format HH:MM:SS.DD,
27
+ * adding hours and minutes only when needed.
28
+ *
29
+ * @param {number} time - The time in seconds to format.
30
+ * @param {FormatTimeOptions} options - The arguments.
31
+ * @returns {string} The formatted time string.
32
+ * @example
33
+ * const formattedTime1 = formatTime( 1234567 ); // Returns "20:34.56"
34
+ * const formattedTime2 = formatTime( 45123 ); // Returns "45.12"
35
+ * const formattedTime3 = formatTime( 64, { addDecimalPart: false } ); // Returns "01:04"
36
+ */
37
+ export function formatTime(time, { addDecimalPart = true } = {}) {
38
+ time = time * 1000;
39
+ const hours = Math.floor(time / 3600000);
40
+ const minutes = Math.floor(time / 60000) % 60;
41
+ const seconds = Math.floor(time / 1000) % 60;
42
+ const deciseconds = Math.floor(time / 10) % 100;
43
+ const parts = [
44
+ hours > 0 ? hours.toString().padStart(2, '0') + ':' : '',
45
+ hours > 0 || minutes > 0 ? minutes.toString().padStart(2, '0') + ':' : '',
46
+ seconds.toString().padStart(2, '0'),
47
+ ];
48
+ if (addDecimalPart) {
49
+ parts.push('.' + deciseconds.toString().padStart(2, '0'));
50
+ }
51
+ return parts.join('');
52
+ }
@@ -0,0 +1,4 @@
1
+ export { default as AIControl } from './ai-control';
2
+ export { default as AiStatusIndicator } from './ai-status-indicator';
3
+ export { default as AudioDurationDisplay } from './audio-duration-display';
4
+ export { GuidelineMessage } from './ai-control/message';
@@ -0,0 +1,4 @@
1
+ export { default as AIControl } from './ai-control';
2
+ export { default as AiStatusIndicator } from './ai-status-indicator';
3
+ export { default as AudioDurationDisplay } from './audio-duration-display';
4
+ export { GuidelineMessage } from './ai-control/message';
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ /**
3
+ * Types & Constants
4
+ */
5
+ import SuggestionsEventSource from '../suggestions-event-source';
6
+ import type { AskQuestionOptionsArgProps } from '../ask-question';
7
+ import type { RequestingErrorProps } from '../hooks/use-ai-suggestions';
8
+ import type { PromptProp } from '../types';
9
+ import type { RequestingStateProp } from '../types';
10
+ export type AiDataContextProps = {
11
+ suggestion: string;
12
+ requestingError: RequestingErrorProps;
13
+ requestingState: RequestingStateProp;
14
+ requestSuggestion: (prompt: PromptProp, options?: AskQuestionOptionsArgProps) => void;
15
+ stopSuggestion: () => void;
16
+ eventSource: SuggestionsEventSource | null;
17
+ };
18
+ type AiDataContextProviderProps = {
19
+ value: AiDataContextProps;
20
+ children: React.ReactElement;
21
+ };
22
+ /**
23
+ * AI Data Context
24
+ *
25
+ * @returns {AiDataContextProps} Context.
26
+ */
27
+ export declare const AiDataContext: React.Context<AiDataContextProps>;
28
+ /**
29
+ * AI Data Context Provider
30
+ *
31
+ * @param {AiDataContextProviderProps} props - Component props.
32
+ * @returns {React.ReactElement} Context provider.
33
+ * @example
34
+ * <AiDataContextProvider value={ value }>
35
+ * { children }
36
+ * </AiDataContextProvider>
37
+ */
38
+ export declare const AiDataContextProvider: ({ value, children, }: AiDataContextProviderProps) => React.ReactElement;
39
+ export {};
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { createContext } from '@wordpress/element';
6
+ /**
7
+ * AI Data Context
8
+ *
9
+ * @returns {AiDataContextProps} Context.
10
+ */
11
+ export const AiDataContext = createContext({});
12
+ /**
13
+ * AI Data Context Provider
14
+ *
15
+ * @param {AiDataContextProviderProps} props - Component props.
16
+ * @returns {React.ReactElement} Context provider.
17
+ * @example
18
+ * <AiDataContextProvider value={ value }>
19
+ * { children }
20
+ * </AiDataContextProvider>
21
+ */
22
+ export const AiDataContextProvider = ({ value, children, }) => (_jsx(AiDataContext.Provider, { value: value, children: children }));
@@ -0,0 +1,3 @@
1
+ export { AiDataContext, AiDataContextProvider } from './context';
2
+ export { default as withAiDataProvider } from './with-ai-assistant-data';
3
+ export { default as useAiContext } from './use-ai-context';
@@ -0,0 +1,3 @@
1
+ export { AiDataContext, AiDataContextProvider } from './context';
2
+ export { default as withAiDataProvider } from './with-ai-assistant-data';
3
+ export { default as useAiContext } from './use-ai-context';
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { RequestingErrorProps } from '../types';
5
+ /**
6
+ * Types & constants
7
+ */
8
+ import type { AiDataContextProps } from './context';
9
+ import type { AskQuestionOptionsArgProps } from '../ask-question';
10
+ export type UseAiContextOptions = {
11
+ askQuestionOptions?: AskQuestionOptionsArgProps;
12
+ onDone?: (content: string) => void;
13
+ onSuggestion?: (suggestion: string) => void;
14
+ onError?: (error: RequestingErrorProps) => void;
15
+ };
16
+ /**
17
+ * useAiContext hook to provide access to
18
+ * the AI Assistant data (from context),
19
+ * and to subscribe to the request events (onDone, onSuggestion).
20
+ *
21
+ * @param {UseAiContextOptions} options - the hook options.
22
+ * @returns {AiDataContextProps} the AI Assistant data context.
23
+ */
24
+ export default function useAiContext({ onDone, onSuggestion, onError, }?: UseAiContextOptions): AiDataContextProps;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { useCallback, useContext, useEffect } from '@wordpress/element';
5
+ /**
6
+ * Internal dependencies
7
+ */
8
+ import { ERROR_RESPONSE } from '../types';
9
+ import { AiDataContext } from '.';
10
+ /**
11
+ * useAiContext hook to provide access to
12
+ * the AI Assistant data (from context),
13
+ * and to subscribe to the request events (onDone, onSuggestion).
14
+ *
15
+ * @param {UseAiContextOptions} options - the hook options.
16
+ * @returns {AiDataContextProps} the AI Assistant data context.
17
+ */
18
+ export default function useAiContext({ onDone, onSuggestion, onError, } = {}) {
19
+ const context = useContext(AiDataContext);
20
+ const { eventSource } = context;
21
+ const done = useCallback((event) => onDone?.(event?.detail), [onDone]);
22
+ const suggestion = useCallback((event) => onSuggestion?.(event?.detail), [onSuggestion]);
23
+ const error = useCallback((event) => {
24
+ onError?.(event?.detail);
25
+ }, []);
26
+ useEffect(() => {
27
+ if (!eventSource) {
28
+ return;
29
+ }
30
+ if (onDone) {
31
+ eventSource.addEventListener('done', done);
32
+ }
33
+ if (onSuggestion) {
34
+ eventSource.addEventListener('suggestion', suggestion);
35
+ }
36
+ if (onError) {
37
+ eventSource.addEventListener(ERROR_RESPONSE, error);
38
+ }
39
+ return () => {
40
+ eventSource.removeEventListener('done', done);
41
+ eventSource.removeEventListener('suggestion', suggestion);
42
+ eventSource.removeEventListener(ERROR_RESPONSE, error);
43
+ };
44
+ }, [eventSource]);
45
+ return context;
46
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ /**
3
+ * High Order Component that provides the
4
+ * AI Assistant Data context to the wrapped component.
5
+ *
6
+ * @param {React.ReactElement} WrappedComponent - component to wrap.
7
+ * @returns {React.ReactElement} Wrapped component, with the AI Assistant Data context.
8
+ */
9
+ declare const withAiDataProvider: (Inner: React.ComponentType<{}>) => (props: any) => import("react/jsx-runtime").JSX.Element;
10
+ export default withAiDataProvider;
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * External Dependencies
4
+ */
5
+ import { createHigherOrderComponent } from '@wordpress/compose';
6
+ import { useMemo } from '@wordpress/element';
7
+ /**
8
+ * Internal Dependencies
9
+ */
10
+ import useAiSuggestions from '../hooks/use-ai-suggestions';
11
+ import { AiDataContextProvider } from '.';
12
+ /**
13
+ * High Order Component that provides the
14
+ * AI Assistant Data context to the wrapped component.
15
+ *
16
+ * @param {React.ReactElement} WrappedComponent - component to wrap.
17
+ * @returns {React.ReactElement} Wrapped component, with the AI Assistant Data context.
18
+ */
19
+ const withAiDataProvider = createHigherOrderComponent((WrappedComponent) => {
20
+ return props => {
21
+ // Connect with the AI Assistant communication layer.
22
+ const { suggestion, error: requestingError, requestingState, request: requestSuggestion, stopSuggestion, eventSource, } = useAiSuggestions();
23
+ // Build the context value to pass to the ai assistant data provider.
24
+ const dataContextValue = useMemo(() => ({
25
+ suggestion,
26
+ requestingError,
27
+ requestingState,
28
+ eventSource,
29
+ requestSuggestion,
30
+ stopSuggestion,
31
+ }), [
32
+ suggestion,
33
+ requestingError,
34
+ requestingState,
35
+ eventSource,
36
+ requestSuggestion,
37
+ stopSuggestion,
38
+ ]);
39
+ return (_jsx(AiDataContextProvider, { value: dataContextValue, children: _jsx(WrappedComponent, { ...props }) }));
40
+ };
41
+ }, 'withAiDataProvider');
42
+ export default withAiDataProvider;