@automattic/jetpack-ai-client 0.6.1 → 0.7.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 (66) hide show
  1. package/CHANGELOG.md +11 -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 +8 -0
  7. package/build/audio-transcription/index.js +49 -0
  8. package/build/components/ai-control/index.d.ts +1 -1
  9. package/build/components/ai-control/index.js +2 -2
  10. package/build/components/ai-status-indicator/index.d.ts +1 -1
  11. package/build/components/audio-duration-display/index.d.ts +3 -2
  12. package/build/components/audio-duration-display/index.js +3 -14
  13. package/build/components/audio-duration-display/lib/media.d.ts +13 -14
  14. package/build/components/audio-duration-display/lib/media.js +7 -32
  15. package/build/components/index.d.ts +4 -4
  16. package/build/components/index.js +4 -4
  17. package/build/data-flow/context.d.ts +5 -5
  18. package/build/data-flow/index.d.ts +3 -3
  19. package/build/data-flow/index.js +3 -3
  20. package/build/data-flow/use-ai-context.d.ts +3 -3
  21. package/build/data-flow/use-ai-context.js +2 -2
  22. package/build/data-flow/with-ai-assistant-data.js +2 -2
  23. package/build/hooks/use-ai-suggestions/index.d.ts +4 -4
  24. package/build/hooks/use-ai-suggestions/index.js +2 -2
  25. package/build/hooks/use-audio-transcription/index.d.ts +24 -0
  26. package/build/hooks/use-audio-transcription/index.js +49 -0
  27. package/build/hooks/use-media-recording/index.d.ts +30 -12
  28. package/build/hooks/use-media-recording/index.js +106 -40
  29. package/build/hooks/use-transcription-post-processing/index.d.ts +30 -0
  30. package/build/hooks/use-transcription-post-processing/index.js +84 -0
  31. package/build/icons/index.d.ts +7 -7
  32. package/build/icons/index.js +7 -7
  33. package/build/icons/mic.js +2 -2
  34. package/build/icons/player-pause.js +1 -1
  35. package/build/index.d.ts +12 -9
  36. package/build/index.js +12 -9
  37. package/build/jwt/index.js +4 -1
  38. package/build/suggestions-event-source/index.d.ts +1 -1
  39. package/build/suggestions-event-source/index.js +3 -3
  40. package/build/types.d.ts +5 -2
  41. package/build/types.js +4 -0
  42. package/package.json +2 -2
  43. package/src/api-fetch/index.ts +13 -0
  44. package/src/ask-question/index.ts +2 -2
  45. package/src/audio-transcription/index.ts +67 -0
  46. package/src/components/ai-control/index.tsx +3 -3
  47. package/src/components/ai-status-indicator/index.tsx +1 -1
  48. package/src/components/audio-duration-display/index.tsx +6 -17
  49. package/src/components/audio-duration-display/lib/media.ts +17 -40
  50. package/src/components/index.ts +4 -4
  51. package/src/data-flow/context.tsx +5 -5
  52. package/src/data-flow/index.ts +3 -3
  53. package/src/data-flow/use-ai-context.ts +4 -4
  54. package/src/data-flow/with-ai-assistant-data.tsx +2 -2
  55. package/src/hooks/use-ai-suggestions/index.ts +6 -6
  56. package/src/hooks/use-audio-transcription/index.ts +81 -0
  57. package/src/hooks/use-media-recording/Readme.md +2 -2
  58. package/src/hooks/use-media-recording/index.ts +161 -58
  59. package/src/hooks/use-transcription-post-processing/index.ts +135 -0
  60. package/src/icons/index.ts +7 -7
  61. package/src/icons/mic.tsx +14 -16
  62. package/src/icons/player-pause.tsx +5 -5
  63. package/src/index.ts +12 -9
  64. package/src/jwt/index.ts +4 -1
  65. package/src/suggestions-event-source/index.ts +4 -4
  66. package/src/types.ts +19 -2
package/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ 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.7.0] - 2024-02-19
9
+ ### Added
10
+ - AI Client: add support for audio transcriptions. [#35691]
11
+ - AI Client: add support for transcription post-processing. [#35734]
12
+
13
+ ### Changed
14
+ - AI Client: Update voice to content feature [#35698]
15
+ - Make build usable in projects using tsc with `moduleResolution` set to 'nodenext'. [#35453]
16
+ - Voice to Content: Add states and refactor duration calculation [#35717]
17
+
8
18
  ## [0.6.1] - 2024-02-13
9
19
  ### Changed
10
20
  - Updated package dependencies. [#35608]
@@ -210,6 +220,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
210
220
  - Updated package dependencies. [#31659]
211
221
  - Updated package dependencies. [#31785]
212
222
 
223
+ [0.7.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.6.1...v0.7.0
213
224
  [0.6.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.6.0...v0.6.1
214
225
  [0.6.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.5.1...v0.6.0
215
226
  [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,8 @@
1
+ /**
2
+ * A function that takes an audio blob and transcribes it.
3
+ *
4
+ * @param {Blob} audio - The audio to be transcribed, from a recording or from a file.
5
+ * @param {string} feature - The feature name that is calling the transcription.
6
+ * @returns {Promise<string>} - The promise of a string containing the transcribed audio.
7
+ */
8
+ export default function transcribeAudio(audio: Blob, feature?: string): Promise<string>;
@@ -0,0 +1,49 @@
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
+ debug('Transcribing audio: %o. Feature: %o', audio, feature);
20
+ // Get a token to use the transcription service
21
+ let token = '';
22
+ try {
23
+ token = (await requestJwt()).token;
24
+ }
25
+ catch (error) {
26
+ debug('Error getting token: %o', error);
27
+ return Promise.reject(error);
28
+ }
29
+ // Build a FormData object to hold the audio file
30
+ const formData = new FormData();
31
+ formData.append('audio_file', audio);
32
+ try {
33
+ const headers = {
34
+ Authorization: `Bearer ${token}`,
35
+ };
36
+ const response = await apiFetch({
37
+ url: `https://public-api.wordpress.com/wpcom/v2/jetpack-ai-transcription${feature ? `?feature=${feature}` : ''}`,
38
+ method: 'POST',
39
+ body: formData,
40
+ headers,
41
+ });
42
+ debug('Transcription response: %o', response);
43
+ return response.text;
44
+ }
45
+ catch (error) {
46
+ debug('Transcription error response: %o', error);
47
+ return Promise.reject(error);
48
+ }
49
+ }
@@ -6,7 +6,7 @@ import './style.scss';
6
6
  /**
7
7
  * Types
8
8
  */
9
- import type { RequestingStateProp } from '../../types';
9
+ import type { RequestingStateProp } from '../../types.js';
10
10
  type AiControlProps = {
11
11
  disabled?: boolean;
12
12
  value: string;
@@ -14,8 +14,8 @@ import React from 'react';
14
14
  * Internal dependencies
15
15
  */
16
16
  import './style.scss';
17
- import AiStatusIndicator from '../ai-status-indicator';
18
- import { GuidelineMessage } from './message';
17
+ import AiStatusIndicator from '../ai-status-indicator/index.js';
18
+ import { GuidelineMessage } from './message.js';
19
19
  // eslint-disable-next-line @typescript-eslint/no-empty-function
20
20
  const noop = () => { };
21
21
  /**
@@ -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, 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, default as FooterMessage } from './ai-control/message.js';
@@ -2,11 +2,11 @@ import React from 'react';
2
2
  /**
3
3
  * Types & Constants
4
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';
5
+ import SuggestionsEventSource from '../suggestions-event-source/index.js';
6
+ import type { AskQuestionOptionsArgProps } from '../ask-question/index.js';
7
+ import type { RequestingErrorProps } from '../hooks/use-ai-suggestions/index.js';
8
+ import type { PromptProp } from '../types.js';
9
+ import type { RequestingStateProp } from '../types.js';
10
10
  export type AiDataContextProps = {
11
11
  suggestion: string;
12
12
  requestingError: RequestingErrorProps;
@@ -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;
@@ -5,8 +5,8 @@ import { useCallback, useContext, useEffect } from '@wordpress/element';
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,24 @@
1
+ /**
2
+ * The response from the audio transcription hook.
3
+ */
4
+ export type UseAudioTranscriptionReturn = {
5
+ transcriptionResult: string;
6
+ isTranscribingAudio: boolean;
7
+ transcriptionError: string;
8
+ transcribeAudio: (audio: Blob) => void;
9
+ };
10
+ /**
11
+ * The props for the audio transcription hook.
12
+ */
13
+ export type UseAudioTranscriptionProps = {
14
+ feature: string;
15
+ onReady?: (transcription: string) => void;
16
+ onError?: (error: string) => void;
17
+ };
18
+ /**
19
+ * A hook to handle audio transcription.
20
+ *
21
+ * @param {string} feature - The feature name that is calling the transcription.
22
+ * @returns {UseAudioTranscriptionReturn} - Object with properties to get the transcription data.
23
+ */
24
+ export default function useAudioTranscription({ feature, onReady, onError, }: UseAudioTranscriptionProps): UseAudioTranscriptionReturn;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { useCallback, useState } from '@wordpress/element';
5
+ import debugFactory from 'debug';
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import transcribeAudio from '../../audio-transcription/index.js';
10
+ const debug = debugFactory('jetpack-ai-client:use-audio-transcription');
11
+ /**
12
+ * A hook to handle audio transcription.
13
+ *
14
+ * @param {string} feature - The feature name that is calling the transcription.
15
+ * @returns {UseAudioTranscriptionReturn} - Object with properties to get the transcription data.
16
+ */
17
+ export default function useAudioTranscription({ feature, onReady, onError, }) {
18
+ const [transcriptionResult, setTranscriptionResult] = useState('');
19
+ const [transcriptionError, setTranscriptionError] = useState('');
20
+ const [isTranscribingAudio, setIsTranscribingAudio] = useState(false);
21
+ const handleAudioTranscription = useCallback((audio) => {
22
+ debug('Transcribing audio');
23
+ /**
24
+ * Reset the transcription result and error.
25
+ */
26
+ setTranscriptionResult('');
27
+ setTranscriptionError('');
28
+ setIsTranscribingAudio(true);
29
+ /**
30
+ * Call the audio transcription library.
31
+ */
32
+ transcribeAudio(audio, feature)
33
+ .then(transcriptionText => {
34
+ setTranscriptionResult(transcriptionText);
35
+ onReady?.(transcriptionText);
36
+ })
37
+ .catch(error => {
38
+ setTranscriptionError(error.message);
39
+ onError?.(error.message);
40
+ })
41
+ .finally(() => setIsTranscribingAudio(false));
42
+ }, [transcribeAudio, setTranscriptionResult, setTranscriptionError, setIsTranscribingAudio]);
43
+ return {
44
+ transcriptionResult,
45
+ isTranscribingAudio,
46
+ transcriptionError,
47
+ transcribeAudio: handleAudioTranscription,
48
+ };
49
+ }
@@ -1,6 +1,6 @@
1
- type RecordingStateProp = 'inactive' | 'recording' | 'paused';
1
+ type RecordingStateProp = 'inactive' | 'recording' | 'paused' | 'processing' | 'error';
2
2
  type UseMediaRecordingProps = {
3
- onDone?: (blob: Blob) => void;
3
+ onDone?: (blob: Blob, url: string) => void;
4
4
  };
5
5
  type UseMediaRecordingReturn = {
6
6
  /**
@@ -16,21 +16,39 @@ type UseMediaRecordingReturn = {
16
16
  */
17
17
  url: string | null;
18
18
  /**
19
- * `start` recording handler
19
+ * The error message
20
20
  */
21
- start: (timeslice?: number) => void;
21
+ error: string | null;
22
22
  /**
23
- * `pause` recording handler
23
+ * The duration of the recorded audio
24
24
  */
25
- pause: () => void;
25
+ duration: number;
26
26
  /**
27
- * `resume` recording handler
27
+ * The error handler
28
28
  */
29
- resume: () => void;
30
- /**
31
- * `stop` recording handler
32
- */
33
- stop: () => void;
29
+ onError: (err: string | Error) => void;
30
+ controls: {
31
+ /**
32
+ * `start` recording handler
33
+ */
34
+ start: (timeslice?: number) => void;
35
+ /**
36
+ * `pause` recording handler
37
+ */
38
+ pause: () => void;
39
+ /**
40
+ * `resume` recording handler
41
+ */
42
+ resume: () => void;
43
+ /**
44
+ * `stop` recording handler
45
+ */
46
+ stop: () => void;
47
+ /**
48
+ * `reset` recording handler
49
+ */
50
+ reset: () => void;
51
+ };
34
52
  };
35
53
  /**
36
54
  * react custom hook to handle media recording.