@automattic/jetpack-ai-client 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,10 @@ 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.1] - 2024-02-27
9
+ ### Changed
10
+ - AI Client: support audio transcription and transcription post-processing canceling. [#35923]
11
+
8
12
  ## [0.8.0] - 2024-02-26
9
13
  ### Added
10
14
  - Add upgrade message for free tier [#35794]
@@ -229,6 +233,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
229
233
  - Updated package dependencies. [#31659]
230
234
  - Updated package dependencies. [#31785]
231
235
 
236
+ [0.8.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.8.0...v0.8.1
232
237
  [0.8.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.7.0...v0.8.0
233
238
  [0.7.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.6.1...v0.7.0
234
239
  [0.6.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.6.0...v0.6.1
@@ -1,12 +1,9 @@
1
- /**
2
- * Types
3
- */
4
- import { CancelablePromise } from '../types.js';
5
1
  /**
6
2
  * A function that takes an audio blob and transcribes it.
7
3
  *
8
4
  * @param {Blob} audio - The audio to be transcribed, from a recording or from a file.
9
5
  * @param {string} feature - The feature name that is calling the transcription.
6
+ * @param {AbortSignal} requestAbortSignal - The signal to abort the request.
10
7
  * @returns {Promise<string>} - The promise of a string containing the transcribed audio.
11
8
  */
12
- export default function transcribeAudio(audio: Blob, feature?: string): CancelablePromise<string>;
9
+ export default function transcribeAudio(audio: Blob, feature?: string, requestAbortSignal?: AbortSignal): Promise<string>;
@@ -13,11 +13,10 @@ const debug = debugFactory('jetpack-ai-client:audio-transcription');
13
13
  *
14
14
  * @param {Blob} audio - The audio to be transcribed, from a recording or from a file.
15
15
  * @param {string} feature - The feature name that is calling the transcription.
16
+ * @param {AbortSignal} requestAbortSignal - The signal to abort the request.
16
17
  * @returns {Promise<string>} - The promise of a string containing the transcribed audio.
17
18
  */
18
- export default async function transcribeAudio(audio, feature
19
- // @ts-expect-error Promises are not cancelable by default
20
- ) {
19
+ export default async function transcribeAudio(audio, feature, requestAbortSignal) {
21
20
  debug('Transcribing audio: %o. Feature: %o', audio, feature);
22
21
  // Get a token to use the transcription service
23
22
  let token = '';
@@ -40,6 +39,7 @@ export default async function transcribeAudio(audio, feature
40
39
  method: 'POST',
41
40
  body: formData,
42
41
  headers,
42
+ signal: requestAbortSignal ?? undefined,
43
43
  });
44
44
  debug('Transcription response: %o', response);
45
45
  return response.text;
@@ -1,7 +1,3 @@
1
- /**
2
- * Types
3
- */
4
- import type { CancelablePromise } from '../../types.js';
5
1
  /**
6
2
  * The response from the audio transcription hook.
7
3
  */
@@ -9,7 +5,8 @@ export type UseAudioTranscriptionReturn = {
9
5
  transcriptionResult: string;
10
6
  isTranscribingAudio: boolean;
11
7
  transcriptionError: string;
12
- transcribeAudio: (audio: Blob) => CancelablePromise;
8
+ transcribeAudio: (audio: Blob) => void;
9
+ cancelTranscription: () => void;
13
10
  };
14
11
  /**
15
12
  * The props for the audio transcription hook.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { useCallback, useState } from '@wordpress/element';
4
+ import { useCallback, useState, useRef } from '@wordpress/element';
5
5
  import debugFactory from 'debug';
6
6
  /**
7
7
  * Internal dependencies
@@ -18,6 +18,7 @@ export default function useAudioTranscription({ feature, onReady, onError, }) {
18
18
  const [transcriptionResult, setTranscriptionResult] = useState('');
19
19
  const [transcriptionError, setTranscriptionError] = useState('');
20
20
  const [isTranscribingAudio, setIsTranscribingAudio] = useState(false);
21
+ const abortController = useRef(null);
21
22
  const handleAudioTranscription = useCallback((audio) => {
22
23
  debug('Transcribing audio');
23
24
  /**
@@ -26,31 +27,44 @@ export default function useAudioTranscription({ feature, onReady, onError, }) {
26
27
  setTranscriptionResult('');
27
28
  setTranscriptionError('');
28
29
  setIsTranscribingAudio(true);
30
+ /*
31
+ * Create an AbortController to cancel the transcription.
32
+ */
33
+ const controller = new AbortController();
34
+ abortController.current = controller;
29
35
  /**
30
36
  * Call the audio transcription library.
31
37
  */
32
- const promise = transcribeAudio(audio, feature)
38
+ transcribeAudio(audio, feature, controller.signal)
33
39
  .then(transcriptionText => {
34
- if (promise.canceled) {
35
- return;
36
- }
37
40
  setTranscriptionResult(transcriptionText);
38
41
  onReady?.(transcriptionText);
39
42
  })
40
43
  .catch(error => {
41
- if (promise.canceled) {
42
- return;
44
+ if (!controller.signal.aborted) {
45
+ setTranscriptionError(error.message);
46
+ onError?.(error.message);
43
47
  }
44
- setTranscriptionError(error.message);
45
- onError?.(error.message);
46
48
  })
47
49
  .finally(() => setIsTranscribingAudio(false));
48
- return promise;
49
50
  }, [transcribeAudio, setTranscriptionResult, setTranscriptionError, setIsTranscribingAudio]);
51
+ const handleAudioTranscriptionCancel = useCallback(() => {
52
+ /*
53
+ * Cancel the transcription.
54
+ */
55
+ abortController.current?.abort();
56
+ /*
57
+ * Reset the transcription result and error.
58
+ */
59
+ setTranscriptionResult('');
60
+ setTranscriptionError('');
61
+ setIsTranscribingAudio(false);
62
+ }, [abortController, setTranscriptionResult, setTranscriptionError, setIsTranscribingAudio]);
50
63
  return {
51
64
  transcriptionResult,
52
65
  isTranscribingAudio,
53
66
  transcriptionError,
54
67
  transcribeAudio: handleAudioTranscription,
68
+ cancelTranscription: handleAudioTranscriptionCancel,
55
69
  };
56
70
  }
@@ -11,6 +11,7 @@ export type UseTranscriptionPostProcessingReturn = {
11
11
  isProcessingTranscription: boolean;
12
12
  postProcessingError: string;
13
13
  processTranscription: (action: PostProcessingAction, transcription: string) => void;
14
+ cancelTranscriptionProcessing: () => void;
14
15
  };
15
16
  /**
16
17
  * The props for the transcription post-processing hook.
@@ -38,7 +38,7 @@ export default function useTranscriptionPostProcessing({ feature, onReady, onErr
38
38
  setPostProcessingError(errorData.message);
39
39
  onError?.(errorData.message);
40
40
  }, [setPostProcessingError, onError]);
41
- const { request } = useAiSuggestions({
41
+ const { request, stopSuggestion } = useAiSuggestions({
42
42
  autoRequest: false,
43
43
  onSuggestion: handleOnSuggestion,
44
44
  onDone: handleOnDone,
@@ -75,10 +75,18 @@ export default function useTranscriptionPostProcessing({ feature, onReady, onErr
75
75
  request,
76
76
  feature,
77
77
  ]);
78
+ const handleTranscriptionPostProcessingCancel = useCallback(() => {
79
+ /*
80
+ * Stop the suggestion streaming.
81
+ */
82
+ stopSuggestion();
83
+ setIsProcessingTranscription(false);
84
+ }, [stopSuggestion, setIsProcessingTranscription]);
78
85
  return {
79
86
  postProcessingResult,
80
87
  isProcessingTranscription,
81
88
  postProcessingError,
82
89
  processTranscription: handleTranscriptionPostProcessing,
90
+ cancelTranscriptionProcessing: handleTranscriptionPostProcessingCancel,
83
91
  };
84
92
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@automattic/jetpack-ai-client",
4
- "version": "0.8.0",
4
+ "version": "0.8.1",
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": {
@@ -39,8 +39,8 @@
39
39
  "types": "./build/index.d.ts",
40
40
  "dependencies": {
41
41
  "@automattic/jetpack-base-styles": "^0.6.17",
42
- "@automattic/jetpack-connection": "^0.32.3",
43
- "@automattic/jetpack-shared-extension-utils": "^0.14.2",
42
+ "@automattic/jetpack-connection": "^0.32.4",
43
+ "@automattic/jetpack-shared-extension-utils": "^0.14.3",
44
44
  "@microsoft/fetch-event-source": "2.0.1",
45
45
  "@types/react": "18.2.33",
46
46
  "@wordpress/api-fetch": "6.48.0",
@@ -7,10 +7,6 @@ import debugFactory from 'debug';
7
7
  */
8
8
  import apiFetch from '../api-fetch/index.js';
9
9
  import requestJwt from '../jwt/index.js';
10
- /**
11
- * Types
12
- */
13
- import { CancelablePromise } from '../types.js';
14
10
 
15
11
  const debug = debugFactory( 'jetpack-ai-client:audio-transcription' );
16
12
 
@@ -29,13 +25,14 @@ type AudioTranscriptionResponse = {
29
25
  *
30
26
  * @param {Blob} audio - The audio to be transcribed, from a recording or from a file.
31
27
  * @param {string} feature - The feature name that is calling the transcription.
28
+ * @param {AbortSignal} requestAbortSignal - The signal to abort the request.
32
29
  * @returns {Promise<string>} - The promise of a string containing the transcribed audio.
33
30
  */
34
31
  export default async function transcribeAudio(
35
32
  audio: Blob,
36
- feature?: string
37
- // @ts-expect-error Promises are not cancelable by default
38
- ): CancelablePromise< string > {
33
+ feature?: string,
34
+ requestAbortSignal?: AbortSignal
35
+ ): Promise< string > {
39
36
  debug( 'Transcribing audio: %o. Feature: %o', audio, feature );
40
37
 
41
38
  // Get a token to use the transcription service
@@ -63,6 +60,7 @@ export default async function transcribeAudio(
63
60
  method: 'POST',
64
61
  body: formData,
65
62
  headers,
63
+ signal: requestAbortSignal ?? undefined,
66
64
  } );
67
65
 
68
66
  debug( 'Transcription response: %o', response );
@@ -1,16 +1,12 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { useCallback, useState } from '@wordpress/element';
4
+ import { useCallback, useState, useRef } from '@wordpress/element';
5
5
  import debugFactory from 'debug';
6
6
  /**
7
7
  * Internal dependencies
8
8
  */
9
9
  import transcribeAudio from '../../audio-transcription/index.js';
10
- /**
11
- * Types
12
- */
13
- import type { CancelablePromise } from '../../types.js';
14
10
 
15
11
  const debug = debugFactory( 'jetpack-ai-client:use-audio-transcription' );
16
12
 
@@ -21,7 +17,8 @@ export type UseAudioTranscriptionReturn = {
21
17
  transcriptionResult: string;
22
18
  isTranscribingAudio: boolean;
23
19
  transcriptionError: string;
24
- transcribeAudio: ( audio: Blob ) => CancelablePromise;
20
+ transcribeAudio: ( audio: Blob ) => void;
21
+ cancelTranscription: () => void;
25
22
  };
26
23
 
27
24
  /**
@@ -47,6 +44,7 @@ export default function useAudioTranscription( {
47
44
  const [ transcriptionResult, setTranscriptionResult ] = useState< string >( '' );
48
45
  const [ transcriptionError, setTranscriptionError ] = useState< string >( '' );
49
46
  const [ isTranscribingAudio, setIsTranscribingAudio ] = useState( false );
47
+ const abortController = useRef< AbortController >( null );
50
48
 
51
49
  const handleAudioTranscription = useCallback(
52
50
  ( audio: Blob ) => {
@@ -59,37 +57,49 @@ export default function useAudioTranscription( {
59
57
  setTranscriptionError( '' );
60
58
  setIsTranscribingAudio( true );
61
59
 
60
+ /*
61
+ * Create an AbortController to cancel the transcription.
62
+ */
63
+ const controller = new AbortController();
64
+ abortController.current = controller;
65
+
62
66
  /**
63
67
  * Call the audio transcription library.
64
68
  */
65
- const promise: CancelablePromise = transcribeAudio( audio, feature )
69
+ transcribeAudio( audio, feature, controller.signal )
66
70
  .then( transcriptionText => {
67
- if ( promise.canceled ) {
68
- return;
69
- }
70
-
71
71
  setTranscriptionResult( transcriptionText );
72
72
  onReady?.( transcriptionText );
73
73
  } )
74
74
  .catch( error => {
75
- if ( promise.canceled ) {
76
- return;
75
+ if ( ! controller.signal.aborted ) {
76
+ setTranscriptionError( error.message );
77
+ onError?.( error.message );
77
78
  }
78
-
79
- setTranscriptionError( error.message );
80
- onError?.( error.message );
81
79
  } )
82
80
  .finally( () => setIsTranscribingAudio( false ) );
83
-
84
- return promise;
85
81
  },
86
82
  [ transcribeAudio, setTranscriptionResult, setTranscriptionError, setIsTranscribingAudio ]
87
83
  );
88
84
 
85
+ const handleAudioTranscriptionCancel = useCallback( () => {
86
+ /*
87
+ * Cancel the transcription.
88
+ */
89
+ abortController.current?.abort();
90
+ /*
91
+ * Reset the transcription result and error.
92
+ */
93
+ setTranscriptionResult( '' );
94
+ setTranscriptionError( '' );
95
+ setIsTranscribingAudio( false );
96
+ }, [ abortController, setTranscriptionResult, setTranscriptionError, setIsTranscribingAudio ] );
97
+
89
98
  return {
90
99
  transcriptionResult,
91
100
  isTranscribingAudio,
92
101
  transcriptionError,
93
102
  transcribeAudio: handleAudioTranscription,
103
+ cancelTranscription: handleAudioTranscriptionCancel,
94
104
  };
95
105
  }
@@ -25,6 +25,7 @@ export type UseTranscriptionPostProcessingReturn = {
25
25
  isProcessingTranscription: boolean;
26
26
  postProcessingError: string;
27
27
  processTranscription: ( action: PostProcessingAction, transcription: string ) => void;
28
+ cancelTranscriptionProcessing: () => void;
28
29
  };
29
30
 
30
31
  /**
@@ -81,7 +82,7 @@ export default function useTranscriptionPostProcessing( {
81
82
  [ setPostProcessingError, onError ]
82
83
  );
83
84
 
84
- const { request } = useAiSuggestions( {
85
+ const { request, stopSuggestion } = useAiSuggestions( {
85
86
  autoRequest: false,
86
87
  onSuggestion: handleOnSuggestion,
87
88
  onDone: handleOnDone,
@@ -126,10 +127,19 @@ export default function useTranscriptionPostProcessing( {
126
127
  ]
127
128
  );
128
129
 
130
+ const handleTranscriptionPostProcessingCancel = useCallback( () => {
131
+ /*
132
+ * Stop the suggestion streaming.
133
+ */
134
+ stopSuggestion();
135
+ setIsProcessingTranscription( false );
136
+ }, [ stopSuggestion, setIsProcessingTranscription ] );
137
+
129
138
  return {
130
139
  postProcessingResult,
131
140
  isProcessingTranscription,
132
141
  postProcessingError,
133
142
  processTranscription: handleTranscriptionPostProcessing,
143
+ cancelTranscriptionProcessing: handleTranscriptionPostProcessingCancel,
134
144
  };
135
145
  }