@automattic/jetpack-ai-client 0.6.1 → 0.8.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 (71) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/build/api-fetch/index.d.ts +7 -0
  3. package/build/api-fetch/index.js +6 -0
  4. package/build/ask-question/index.d.ts +2 -2
  5. package/build/ask-question/index.js +1 -1
  6. package/build/audio-transcription/index.d.ts +12 -0
  7. package/build/audio-transcription/index.js +51 -0
  8. package/build/components/ai-control/index.d.ts +7 -6
  9. package/build/components/ai-control/index.js +6 -6
  10. package/build/components/ai-control/message.d.ts +10 -0
  11. package/build/components/ai-control/message.js +15 -2
  12. package/build/components/ai-status-indicator/index.d.ts +1 -1
  13. package/build/components/audio-duration-display/index.d.ts +3 -2
  14. package/build/components/audio-duration-display/index.js +3 -14
  15. package/build/components/audio-duration-display/lib/media.d.ts +13 -14
  16. package/build/components/audio-duration-display/lib/media.js +7 -32
  17. package/build/components/index.d.ts +4 -4
  18. package/build/components/index.js +4 -4
  19. package/build/data-flow/context.d.ts +9 -6
  20. package/build/data-flow/context.js +1 -1
  21. package/build/data-flow/index.d.ts +3 -3
  22. package/build/data-flow/index.js +3 -3
  23. package/build/data-flow/use-ai-context.d.ts +3 -3
  24. package/build/data-flow/use-ai-context.js +3 -3
  25. package/build/data-flow/with-ai-assistant-data.js +2 -2
  26. package/build/hooks/use-ai-suggestions/index.d.ts +4 -4
  27. package/build/hooks/use-ai-suggestions/index.js +2 -2
  28. package/build/hooks/use-audio-transcription/index.d.ts +28 -0
  29. package/build/hooks/use-audio-transcription/index.js +56 -0
  30. package/build/hooks/use-media-recording/index.d.ts +34 -12
  31. package/build/hooks/use-media-recording/index.js +116 -41
  32. package/build/hooks/use-transcription-post-processing/index.d.ts +30 -0
  33. package/build/hooks/use-transcription-post-processing/index.js +84 -0
  34. package/build/icons/index.d.ts +7 -7
  35. package/build/icons/index.js +7 -7
  36. package/build/icons/mic.js +2 -2
  37. package/build/icons/player-pause.js +1 -1
  38. package/build/index.d.ts +12 -9
  39. package/build/index.js +12 -9
  40. package/build/jwt/index.js +4 -1
  41. package/build/suggestions-event-source/index.d.ts +1 -1
  42. package/build/suggestions-event-source/index.js +3 -3
  43. package/build/types.d.ts +9 -2
  44. package/build/types.js +4 -0
  45. package/package.json +5 -5
  46. package/src/api-fetch/index.ts +13 -0
  47. package/src/ask-question/index.ts +2 -2
  48. package/src/audio-transcription/index.ts +75 -0
  49. package/src/components/ai-control/index.tsx +12 -16
  50. package/src/components/ai-control/message.tsx +34 -2
  51. package/src/components/ai-control/style.scss +6 -0
  52. package/src/components/ai-status-indicator/index.tsx +1 -1
  53. package/src/components/audio-duration-display/index.tsx +6 -17
  54. package/src/components/audio-duration-display/lib/media.ts +17 -40
  55. package/src/components/index.ts +8 -4
  56. package/src/data-flow/context.tsx +7 -8
  57. package/src/data-flow/index.ts +3 -3
  58. package/src/data-flow/use-ai-context.ts +6 -6
  59. package/src/data-flow/with-ai-assistant-data.tsx +2 -2
  60. package/src/hooks/use-ai-suggestions/index.ts +6 -6
  61. package/src/hooks/use-audio-transcription/index.ts +95 -0
  62. package/src/hooks/use-media-recording/Readme.md +2 -2
  63. package/src/hooks/use-media-recording/index.ts +179 -59
  64. package/src/hooks/use-transcription-post-processing/index.ts +135 -0
  65. package/src/icons/index.ts +7 -7
  66. package/src/icons/mic.tsx +14 -16
  67. package/src/icons/player-pause.tsx +5 -5
  68. package/src/index.ts +12 -9
  69. package/src/jwt/index.ts +4 -1
  70. package/src/suggestions-event-source/index.ts +4 -4
  71. package/src/types.ts +29 -2
package/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ 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.8.0] - 2024-02-26
9
+ ### Added
10
+ - Add upgrade message for free tier [#35794]
11
+
12
+ ### Changed
13
+ - Updated package dependencies. [#35793]
14
+ - Voice to Content: Add audio analyser to media recording hook [#35877]
15
+ - Voice to Content: Make transcriptions cancelable and add onProcess callback [#35737]
16
+
17
+ ## [0.7.0] - 2024-02-19
18
+ ### Added
19
+ - AI Client: add support for audio transcriptions. [#35691]
20
+ - AI Client: add support for transcription post-processing. [#35734]
21
+
22
+ ### Changed
23
+ - AI Client: Update voice to content feature [#35698]
24
+ - Make build usable in projects using tsc with `moduleResolution` set to 'nodenext'. [#35453]
25
+ - Voice to Content: Add states and refactor duration calculation [#35717]
26
+
8
27
  ## [0.6.1] - 2024-02-13
9
28
  ### Changed
10
29
  - Updated package dependencies. [#35608]
@@ -210,6 +229,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
210
229
  - Updated package dependencies. [#31659]
211
230
  - Updated package dependencies. [#31785]
212
231
 
232
+ [0.8.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.7.0...v0.8.0
233
+ [0.7.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.6.1...v0.7.0
213
234
  [0.6.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.6.0...v0.6.1
214
235
  [0.6.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.5.1...v0.6.0
215
236
  [0.5.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.5.0...v0.5.1
@@ -0,0 +1,7 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import apiFetchMod from '@wordpress/api-fetch';
5
+ type ApiFetchType = typeof apiFetchMod.default;
6
+ declare const apiFetch: ApiFetchType;
7
+ export default apiFetch;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import apiFetchMod from '@wordpress/api-fetch';
5
+ const apiFetch = (apiFetchMod.default ?? apiFetchMod);
6
+ export default apiFetch;
@@ -1,5 +1,5 @@
1
- import SuggestionsEventSource from '../suggestions-event-source';
2
- import type { AiModelTypeProp, PromptProp } from '../types';
1
+ import SuggestionsEventSource from '../suggestions-event-source/index.js';
2
+ import type { AiModelTypeProp, PromptProp } from '../types.js';
3
3
  export type AskQuestionOptionsArgProps = {
4
4
  postId?: number;
5
5
  fromCache?: boolean;
@@ -2,7 +2,7 @@
2
2
  * External dependencies
3
3
  */
4
4
  import debugFactory from 'debug';
5
- import SuggestionsEventSource from '../suggestions-event-source';
5
+ import SuggestionsEventSource from '../suggestions-event-source/index.js';
6
6
  const debug = debugFactory('jetpack-ai-client:ask-question');
7
7
  /**
8
8
  * An asynchronous function that asks a question
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Types
3
+ */
4
+ import { CancelablePromise } from '../types.js';
5
+ /**
6
+ * A function that takes an audio blob and transcribes it.
7
+ *
8
+ * @param {Blob} audio - The audio to be transcribed, from a recording or from a file.
9
+ * @param {string} feature - The feature name that is calling the transcription.
10
+ * @returns {Promise<string>} - The promise of a string containing the transcribed audio.
11
+ */
12
+ export default function transcribeAudio(audio: Blob, feature?: string): CancelablePromise<string>;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import debugFactory from 'debug';
5
+ /**
6
+ * Internal dependencies
7
+ */
8
+ import apiFetch from '../api-fetch/index.js';
9
+ import requestJwt from '../jwt/index.js';
10
+ const debug = debugFactory('jetpack-ai-client:audio-transcription');
11
+ /**
12
+ * A function that takes an audio blob and transcribes it.
13
+ *
14
+ * @param {Blob} audio - The audio to be transcribed, from a recording or from a file.
15
+ * @param {string} feature - The feature name that is calling the transcription.
16
+ * @returns {Promise<string>} - The promise of a string containing the transcribed audio.
17
+ */
18
+ export default async function transcribeAudio(audio, feature
19
+ // @ts-expect-error Promises are not cancelable by default
20
+ ) {
21
+ debug('Transcribing audio: %o. Feature: %o', audio, feature);
22
+ // Get a token to use the transcription service
23
+ let token = '';
24
+ try {
25
+ token = (await requestJwt()).token;
26
+ }
27
+ catch (error) {
28
+ debug('Error getting token: %o', error);
29
+ return Promise.reject(error);
30
+ }
31
+ // Build a FormData object to hold the audio file
32
+ const formData = new FormData();
33
+ formData.append('audio_file', audio);
34
+ try {
35
+ const headers = {
36
+ Authorization: `Bearer ${token}`,
37
+ };
38
+ const response = await apiFetch({
39
+ url: `https://public-api.wordpress.com/wpcom/v2/jetpack-ai-transcription${feature ? `?feature=${feature}` : ''}`,
40
+ method: 'POST',
41
+ body: formData,
42
+ headers,
43
+ });
44
+ debug('Transcription response: %o', response);
45
+ return response.text;
46
+ }
47
+ catch (error) {
48
+ debug('Transcription error response: %o', error);
49
+ return Promise.reject(error);
50
+ }
51
+ }
@@ -6,7 +6,8 @@ import './style.scss';
6
6
  /**
7
7
  * Types
8
8
  */
9
- import type { RequestingStateProp } from '../../types';
9
+ import type { RequestingStateProp } from '../../types.js';
10
+ import type { ReactElement } from 'react';
10
11
  type AiControlProps = {
11
12
  disabled?: boolean;
12
13
  value: string;
@@ -17,23 +18,23 @@ type AiControlProps = {
17
18
  isTransparent?: boolean;
18
19
  state?: RequestingStateProp;
19
20
  showGuideLine?: boolean;
20
- customFooter?: React.ReactElement;
21
+ customFooter?: ReactElement;
21
22
  onChange?: (newValue: string) => void;
22
23
  onSend?: (currentValue: string) => void;
23
24
  onStop?: () => void;
24
25
  onAccept?: () => void;
25
26
  onDiscard?: () => void;
26
27
  showRemove?: boolean;
27
- bannerComponent?: React.ReactElement;
28
- errorComponent?: React.ReactElement;
28
+ bannerComponent?: ReactElement;
29
+ errorComponent?: ReactElement;
29
30
  };
30
31
  /**
31
32
  * AI Control component.
32
33
  *
33
34
  * @param {AiControlProps} props - Component props.
34
35
  * @param {React.MutableRefObject} ref - Ref to the component.
35
- * @returns {React.ReactElement} Rendered component.
36
+ * @returns {ReactElement} Rendered component.
36
37
  */
37
- export declare function AIControl({ disabled, value, placeholder, showAccept, acceptLabel, showButtonLabels, isTransparent, state, showGuideLine, customFooter, onChange, onSend, onStop, onAccept, onDiscard, showRemove, bannerComponent, errorComponent, }: AiControlProps, ref: React.MutableRefObject<null>): React.ReactElement;
38
+ export declare function AIControl({ disabled, value, placeholder, showAccept, acceptLabel, showButtonLabels, isTransparent, state, showGuideLine, customFooter, onChange, onSend, onStop, onAccept, onDiscard, showRemove, bannerComponent, errorComponent, }: AiControlProps, ref: React.MutableRefObject<null>): ReactElement;
38
39
  declare const _default: React.ForwardRefExoticComponent<AiControlProps & React.RefAttributes<null>>;
39
40
  export default _default;
@@ -5,17 +5,18 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
5
5
  import { PlainText } from '@wordpress/block-editor';
6
6
  import { Button, ButtonGroup } from '@wordpress/components';
7
7
  import { useKeyboardShortcut } from '@wordpress/compose';
8
- import { forwardRef, useImperativeHandle, useRef, useEffect, useCallback, } from '@wordpress/element';
8
+ import { useImperativeHandle, useRef, useEffect, useCallback } from '@wordpress/element';
9
9
  import { __ } from '@wordpress/i18n';
10
10
  import { Icon, closeSmall, check, arrowUp, trash, reusableBlock } from '@wordpress/icons';
11
11
  import classNames from 'classnames';
12
+ import { forwardRef } from 'react';
12
13
  import React from 'react';
13
14
  /**
14
15
  * Internal dependencies
15
16
  */
16
17
  import './style.scss';
17
- import AiStatusIndicator from '../ai-status-indicator';
18
- import { GuidelineMessage } from './message';
18
+ import AiStatusIndicator from '../ai-status-indicator/index.js';
19
+ import { GuidelineMessage } from './message.js';
19
20
  // eslint-disable-next-line @typescript-eslint/no-empty-function
20
21
  const noop = () => { };
21
22
  /**
@@ -23,10 +24,9 @@ const noop = () => { };
23
24
  *
24
25
  * @param {AiControlProps} props - Component props.
25
26
  * @param {React.MutableRefObject} ref - Ref to the component.
26
- * @returns {React.ReactElement} Rendered component.
27
+ * @returns {ReactElement} Rendered component.
27
28
  */
28
- export function AIControl({ disabled = false, value = '', placeholder = '', showAccept = false, acceptLabel = __('Accept', 'jetpack-ai-client'), showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, customFooter = null, onChange = noop, onSend = noop, onStop = noop, onAccept = noop, onDiscard = null, showRemove = false, bannerComponent = null, errorComponent = null, }, ref // eslint-disable-line @typescript-eslint/ban-types
29
- ) {
29
+ export function AIControl({ disabled = false, value = '', placeholder = '', showAccept = false, acceptLabel = __('Accept', 'jetpack-ai-client'), showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, customFooter = null, onChange = noop, onSend = noop, onStop = noop, onAccept = noop, onDiscard = null, showRemove = false, bannerComponent = null, errorComponent = null, }, ref) {
30
30
  const promptUserInputRef = useRef(null);
31
31
  const loading = state === 'requesting' || state === 'suggesting';
32
32
  const [editRequest, setEditRequest] = React.useState(false);
@@ -27,4 +27,14 @@ export default function Message({ severity, icon, children, }: MessageProps): Re
27
27
  * @returns {React.ReactElement } - Message component.
28
28
  */
29
29
  export declare function GuidelineMessage(): React.ReactElement;
30
+ /**
31
+ * React component to render a upgrade message.
32
+ *
33
+ * @param {number} requestsRemaining - Number of requests remaining.
34
+ * @returns {React.ReactElement } - Message component.
35
+ */
36
+ export declare function UpgradeMessage({ requestsRemaining, onUpgradeClick, }: {
37
+ requestsRemaining: number;
38
+ onUpgradeClick: () => void;
39
+ }): React.ReactElement;
30
40
  export {};
@@ -2,9 +2,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * External dependencies
4
4
  */
5
- import { ExternalLink } from '@wordpress/components';
5
+ import { ExternalLink, Button } from '@wordpress/components';
6
6
  import { createInterpolateElement } from '@wordpress/element';
7
- import { __ } from '@wordpress/i18n';
7
+ import { __, sprintf } from '@wordpress/i18n';
8
8
  import { Icon, warning, info, cancelCircleFilled as error, check as success, } from '@wordpress/icons';
9
9
  import './style.scss';
10
10
  export const MESSAGE_SEVERITY_WARNING = 'warning';
@@ -42,3 +42,16 @@ export function GuidelineMessage() {
42
42
  link: _jsx(ExternalLink, { href: "https://automattic.com/ai-guidelines" }),
43
43
  }) }));
44
44
  }
45
+ /**
46
+ * React component to render a upgrade message.
47
+ *
48
+ * @param {number} requestsRemaining - Number of requests remaining.
49
+ * @returns {React.ReactElement } - Message component.
50
+ */
51
+ export function UpgradeMessage({ requestsRemaining, onUpgradeClick, }) {
52
+ return (_jsx(Message, { severity: MESSAGE_SEVERITY_INFO, children: createInterpolateElement(sprintf(
53
+ // translators: %1$d: number of requests remaining
54
+ __('You have %1$d free requests remaining. <link>Upgrade</link> and avoid interruptions', 'jetpack-ai-client'), requestsRemaining), {
55
+ link: _jsx(Button, { variant: "link", onClick: onUpgradeClick }),
56
+ }) }));
57
+ }
@@ -1,4 +1,4 @@
1
- import type { RequestingStateProp } from '../../types';
1
+ import type { RequestingStateProp } from '../../types.js';
2
2
  export type AiStatusIndicatorIconSize = 24 | 32 | 48 | 64;
3
3
  import type React from 'react';
4
4
  import './style.scss';
@@ -1,6 +1,7 @@
1
1
  import type React from 'react';
2
2
  type AudioDurationDisplayProps = {
3
- url: string;
3
+ duration: number;
4
+ className?: string | null;
4
5
  };
5
6
  /**
6
7
  * AudioDurationDisplay component.
@@ -8,5 +9,5 @@ type AudioDurationDisplayProps = {
8
9
  * @param {AudioDurationDisplayProps} props - Component props.
9
10
  * @returns {React.ReactElement} Rendered component.
10
11
  */
11
- export default function AudioDurationDisplay({ url, }: AudioDurationDisplayProps): React.ReactElement;
12
+ export default function AudioDurationDisplay({ duration, className, }: AudioDurationDisplayProps): React.ReactElement;
12
13
  export {};
@@ -1,25 +1,14 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- /*
3
- * External dependencies
4
- */
5
- import { useState, useEffect } from '@wordpress/element';
6
2
  /*
7
3
  * Internal dependencies
8
4
  */
9
- import { formatTime, getDuration } from './lib/media';
5
+ import { formatTime } from './lib/media.js';
10
6
  /**
11
7
  * AudioDurationDisplay component.
12
8
  *
13
9
  * @param {AudioDurationDisplayProps} props - Component props.
14
10
  * @returns {React.ReactElement} Rendered component.
15
11
  */
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 }) });
12
+ export default function AudioDurationDisplay({ duration, className, }) {
13
+ return _jsx("span", { className: className, children: formatTime(duration, { addDecimalPart: false }) });
25
14
  }
@@ -1,29 +1,28 @@
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
1
  type FormatTimeOptions = {
10
2
  /**
11
3
  * Whether to add the decimal part to the formatted time.
12
- *
13
4
  */
14
5
  addDecimalPart?: boolean;
6
+ /**
7
+ * Whether to show the minutes part of the formatted time even when it's 0.
8
+ */
9
+ showMinutes?: boolean;
10
+ /**
11
+ * Whether to show the hours part of the formatted time even when it's 0.
12
+ */
13
+ showHours?: boolean;
15
14
  };
16
15
  /**
17
16
  * Formats the given time in milliseconds into a string with the format HH:MM:SS.DD,
18
17
  * adding hours and minutes only when needed.
19
18
  *
20
- * @param {number} time - The time in seconds to format.
19
+ * @param {number} time - The time in milliseconds to format.
21
20
  * @param {FormatTimeOptions} options - The arguments.
22
21
  * @returns {string} The formatted time string.
23
22
  * @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"
23
+ * const formattedTime1 = formatTime( 1234567, { addDecimalPart: true } ); // Returns "20:34.56"
24
+ * const formattedTime2 = formatTime( 45123 ); // Returns "00.45"
25
+ * const formattedTime3 = formatTime( 1200, { showHours: true } ); // Returns "00:00:01"
27
26
  */
28
- export declare function formatTime(time: number, { addDecimalPart }?: FormatTimeOptions): string;
27
+ export declare function formatTime(time: number, { addDecimalPart, showMinutes, showHours }?: FormatTimeOptions): string;
29
28
  export {};
@@ -1,48 +1,23 @@
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
1
  /**
26
2
  * Formats the given time in milliseconds into a string with the format HH:MM:SS.DD,
27
3
  * adding hours and minutes only when needed.
28
4
  *
29
- * @param {number} time - The time in seconds to format.
5
+ * @param {number} time - The time in milliseconds to format.
30
6
  * @param {FormatTimeOptions} options - The arguments.
31
7
  * @returns {string} The formatted time string.
32
8
  * @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"
9
+ * const formattedTime1 = formatTime( 1234567, { addDecimalPart: true } ); // Returns "20:34.56"
10
+ * const formattedTime2 = formatTime( 45123 ); // Returns "00.45"
11
+ * const formattedTime3 = formatTime( 1200, { showHours: true } ); // Returns "00:00:01"
36
12
  */
37
- export function formatTime(time, { addDecimalPart = true } = {}) {
38
- time = time * 1000;
13
+ export function formatTime(time, { addDecimalPart = false, showMinutes = true, showHours = false } = {}) {
39
14
  const hours = Math.floor(time / 3600000);
40
15
  const minutes = Math.floor(time / 60000) % 60;
41
16
  const seconds = Math.floor(time / 1000) % 60;
42
17
  const deciseconds = Math.floor(time / 10) % 100;
43
18
  const parts = [
44
- hours > 0 ? hours.toString().padStart(2, '0') + ':' : '',
45
- hours > 0 || minutes > 0 ? minutes.toString().padStart(2, '0') + ':' : '',
19
+ hours > 0 || showHours ? hours.toString().padStart(2, '0') + ':' : '',
20
+ hours > 0 || minutes > 0 || showMinutes ? minutes.toString().padStart(2, '0') + ':' : '',
46
21
  seconds.toString().padStart(2, '0'),
47
22
  ];
48
23
  if (addDecimalPart) {
@@ -1,4 +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, default as FooterMessage } from './ai-control/message';
1
+ export { default as AIControl } from './ai-control/index.js';
2
+ export { default as AiStatusIndicator } from './ai-status-indicator/index.js';
3
+ export { default as AudioDurationDisplay } from './audio-duration-display/index.js';
4
+ export { GuidelineMessage, UpgradeMessage, default as FooterMessage, } from './ai-control/message.js';
@@ -1,4 +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, default as FooterMessage } from './ai-control/message';
1
+ export { default as AIControl } from './ai-control/index.js';
2
+ export { default as AiStatusIndicator } from './ai-status-indicator/index.js';
3
+ export { default as AudioDurationDisplay } from './audio-duration-display/index.js';
4
+ export { GuidelineMessage, UpgradeMessage, default as FooterMessage, } from './ai-control/message.js';
@@ -1,12 +1,15 @@
1
+ /**
2
+ * External dependencies
3
+ */
1
4
  import React from 'react';
2
5
  /**
3
6
  * Types & Constants
4
7
  */
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';
8
+ import SuggestionsEventSource from '../suggestions-event-source/index.js';
9
+ import type { AskQuestionOptionsArgProps } from '../ask-question/index.js';
10
+ import type { RequestingErrorProps } from '../hooks/use-ai-suggestions/index.js';
11
+ import type { PromptProp } from '../types.js';
12
+ import type { RequestingStateProp } from '../types.js';
10
13
  export type AiDataContextProps = {
11
14
  suggestion: string;
12
15
  requestingError: RequestingErrorProps;
@@ -24,7 +27,7 @@ type AiDataContextProviderProps = {
24
27
  *
25
28
  * @returns {AiDataContextProps} Context.
26
29
  */
27
- export declare const AiDataContext: React.Context<AiDataContextProps>;
30
+ export declare const AiDataContext: React.Context<object | AiDataContextProps>;
28
31
  /**
29
32
  * AI Data Context Provider
30
33
  *
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  /**
3
3
  * External dependencies
4
4
  */
5
- import { createContext } from '@wordpress/element';
5
+ import { createContext } from 'react';
6
6
  /**
7
7
  * AI Data Context
8
8
  *
@@ -1,3 +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';
1
+ export { AiDataContext, AiDataContextProvider } from './context.js';
2
+ export { default as withAiDataProvider } from './with-ai-assistant-data.js';
3
+ export { default as useAiContext } from './use-ai-context.js';
@@ -1,3 +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';
1
+ export { AiDataContext, AiDataContextProvider } from './context.js';
2
+ export { default as withAiDataProvider } from './with-ai-assistant-data.js';
3
+ export { default as useAiContext } from './use-ai-context.js';
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import { RequestingErrorProps } from '../types';
4
+ import { RequestingErrorProps } from '../types.js';
5
5
  /**
6
6
  * Types & constants
7
7
  */
8
- import type { AiDataContextProps } from './context';
9
- import type { AskQuestionOptionsArgProps } from '../ask-question';
8
+ import type { AiDataContextProps } from './context.js';
9
+ import type { AskQuestionOptionsArgProps } from '../ask-question/index.js';
10
10
  export type UseAiContextOptions = {
11
11
  askQuestionOptions?: AskQuestionOptionsArgProps;
12
12
  onDone?: (content: string) => void;
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { useCallback, useContext, useEffect } from '@wordpress/element';
4
+ import { useCallback, useContext, useEffect } from 'react';
5
5
  /**
6
6
  * Internal dependencies
7
7
  */
8
- import { ERROR_RESPONSE } from '../types';
9
- import { AiDataContext } from '.';
8
+ import { ERROR_RESPONSE } from '../types.js';
9
+ import { AiDataContext } from './index.js';
10
10
  /**
11
11
  * useAiContext hook to provide access to
12
12
  * the AI Assistant data (from context),
@@ -7,8 +7,8 @@ import { useMemo } from '@wordpress/element';
7
7
  /**
8
8
  * Internal Dependencies
9
9
  */
10
- import useAiSuggestions from '../hooks/use-ai-suggestions';
11
- import { AiDataContextProvider } from '.';
10
+ import useAiSuggestions from '../hooks/use-ai-suggestions/index.js';
11
+ import { AiDataContextProvider } from './index.js';
12
12
  /**
13
13
  * High Order Component that provides the
14
14
  * AI Assistant Data context to the wrapped component.
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Types & constants
3
3
  */
4
- import type { AskQuestionOptionsArgProps } from '../../ask-question';
5
- import type SuggestionsEventSource from '../../suggestions-event-source';
6
- import type { PromptProp, SuggestionErrorCode } from '../../types';
7
- import type { RequestingStateProp } from '../../types';
4
+ import type { AskQuestionOptionsArgProps } from '../../ask-question/index.js';
5
+ import type SuggestionsEventSource from '../../suggestions-event-source/index.js';
6
+ import type { PromptProp, SuggestionErrorCode } from '../../types.js';
7
+ import type { RequestingStateProp } from '../../types.js';
8
8
  export type RequestingErrorProps = {
9
9
  code: SuggestionErrorCode;
10
10
  message: string;
@@ -7,8 +7,8 @@ import debugFactory from 'debug';
7
7
  /**
8
8
  * Internal dependencies
9
9
  */
10
- import askQuestion from '../../ask-question';
11
- import { ERROR_MODERATION, ERROR_NETWORK, ERROR_QUOTA_EXCEEDED, ERROR_SERVICE_UNAVAILABLE, ERROR_UNCLEAR_PROMPT, } from '../../types';
10
+ import askQuestion from '../../ask-question/index.js';
11
+ import { ERROR_MODERATION, ERROR_NETWORK, ERROR_QUOTA_EXCEEDED, ERROR_SERVICE_UNAVAILABLE, ERROR_UNCLEAR_PROMPT, } from '../../types.js';
12
12
  const debug = debugFactory('jetpack-ai-client:use-suggestion');
13
13
  /**
14
14
  * Get the error data for a given error code.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Types
3
+ */
4
+ import type { CancelablePromise } from '../../types.js';
5
+ /**
6
+ * The response from the audio transcription hook.
7
+ */
8
+ export type UseAudioTranscriptionReturn = {
9
+ transcriptionResult: string;
10
+ isTranscribingAudio: boolean;
11
+ transcriptionError: string;
12
+ transcribeAudio: (audio: Blob) => CancelablePromise;
13
+ };
14
+ /**
15
+ * The props for the audio transcription hook.
16
+ */
17
+ export type UseAudioTranscriptionProps = {
18
+ feature: string;
19
+ onReady?: (transcription: string) => void;
20
+ onError?: (error: string) => void;
21
+ };
22
+ /**
23
+ * A hook to handle audio transcription.
24
+ *
25
+ * @param {string} feature - The feature name that is calling the transcription.
26
+ * @returns {UseAudioTranscriptionReturn} - Object with properties to get the transcription data.
27
+ */
28
+ export default function useAudioTranscription({ feature, onReady, onError, }: UseAudioTranscriptionProps): UseAudioTranscriptionReturn;