cactus-react-native 1.4.0 → 1.5.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 (88) hide show
  1. package/README.md +212 -27
  2. package/android/src/main/jniLibs/arm64-v8a/libcactus.a +0 -0
  3. package/cpp/HybridCactus.cpp +119 -0
  4. package/cpp/HybridCactus.hpp +13 -0
  5. package/cpp/cactus_ffi.h +24 -0
  6. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_ffi.h +24 -0
  7. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_utils.h +41 -1
  8. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/engine.h +66 -48
  9. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/gemma_tools.h +549 -0
  10. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/graph.h +102 -21
  11. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel.h +45 -195
  12. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel_utils.h +399 -140
  13. package/ios/cactus.xcframework/ios-arm64/cactus.framework/cactus +0 -0
  14. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_ffi.h +24 -0
  15. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_utils.h +41 -1
  16. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/engine.h +66 -48
  17. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/gemma_tools.h +549 -0
  18. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/graph.h +102 -21
  19. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel.h +45 -195
  20. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel_utils.h +399 -140
  21. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/cactus +0 -0
  22. package/lib/module/api/Database.js +0 -92
  23. package/lib/module/api/Database.js.map +1 -1
  24. package/lib/module/classes/CactusLM.js +33 -15
  25. package/lib/module/classes/CactusLM.js.map +1 -1
  26. package/lib/module/classes/CactusSTT.js +90 -15
  27. package/lib/module/classes/CactusSTT.js.map +1 -1
  28. package/lib/module/hooks/useCactusLM.js +14 -5
  29. package/lib/module/hooks/useCactusLM.js.map +1 -1
  30. package/lib/module/hooks/useCactusSTT.js +100 -4
  31. package/lib/module/hooks/useCactusSTT.js.map +1 -1
  32. package/lib/module/index.js.map +1 -1
  33. package/lib/module/models.js +336 -0
  34. package/lib/module/models.js.map +1 -0
  35. package/lib/module/native/Cactus.js +37 -0
  36. package/lib/module/native/Cactus.js.map +1 -1
  37. package/lib/module/types/CactusLM.js +2 -0
  38. package/lib/module/types/CactusSTT.js +2 -0
  39. package/lib/module/types/common.js +2 -0
  40. package/lib/module/types/{CactusModel.js.map → common.js.map} +1 -1
  41. package/lib/typescript/src/api/Database.d.ts +0 -6
  42. package/lib/typescript/src/api/Database.d.ts.map +1 -1
  43. package/lib/typescript/src/classes/CactusLM.d.ts +7 -3
  44. package/lib/typescript/src/classes/CactusLM.d.ts.map +1 -1
  45. package/lib/typescript/src/classes/CactusSTT.d.ts +13 -4
  46. package/lib/typescript/src/classes/CactusSTT.d.ts.map +1 -1
  47. package/lib/typescript/src/hooks/useCactusLM.d.ts +2 -2
  48. package/lib/typescript/src/hooks/useCactusLM.d.ts.map +1 -1
  49. package/lib/typescript/src/hooks/useCactusSTT.d.ts +12 -4
  50. package/lib/typescript/src/hooks/useCactusSTT.d.ts.map +1 -1
  51. package/lib/typescript/src/index.d.ts +2 -3
  52. package/lib/typescript/src/index.d.ts.map +1 -1
  53. package/lib/typescript/src/models.d.ts +6 -0
  54. package/lib/typescript/src/models.d.ts.map +1 -0
  55. package/lib/typescript/src/native/Cactus.d.ts +6 -1
  56. package/lib/typescript/src/native/Cactus.d.ts.map +1 -1
  57. package/lib/typescript/src/specs/Cactus.nitro.d.ts +5 -0
  58. package/lib/typescript/src/specs/Cactus.nitro.d.ts.map +1 -1
  59. package/lib/typescript/src/types/CactusLM.d.ts +2 -0
  60. package/lib/typescript/src/types/CactusLM.d.ts.map +1 -1
  61. package/lib/typescript/src/types/CactusSTT.d.ts +20 -0
  62. package/lib/typescript/src/types/CactusSTT.d.ts.map +1 -1
  63. package/lib/typescript/src/types/common.d.ts +28 -0
  64. package/lib/typescript/src/types/common.d.ts.map +1 -0
  65. package/nitrogen/generated/shared/c++/HybridCactusSpec.cpp +5 -0
  66. package/nitrogen/generated/shared/c++/HybridCactusSpec.hpp +5 -0
  67. package/package.json +1 -1
  68. package/src/api/Database.ts +0 -133
  69. package/src/classes/CactusLM.ts +49 -17
  70. package/src/classes/CactusSTT.ts +118 -17
  71. package/src/hooks/useCactusLM.ts +25 -5
  72. package/src/hooks/useCactusSTT.ts +117 -5
  73. package/src/index.tsx +6 -2
  74. package/src/models.ts +344 -0
  75. package/src/native/Cactus.ts +55 -0
  76. package/src/specs/Cactus.nitro.ts +5 -0
  77. package/src/types/CactusLM.ts +3 -0
  78. package/src/types/CactusSTT.ts +26 -0
  79. package/src/types/common.ts +28 -0
  80. package/lib/module/types/CactusModel.js +0 -2
  81. package/lib/module/types/CactusSTTModel.js +0 -2
  82. package/lib/module/types/CactusSTTModel.js.map +0 -1
  83. package/lib/typescript/src/types/CactusModel.d.ts +0 -13
  84. package/lib/typescript/src/types/CactusModel.d.ts.map +0 -1
  85. package/lib/typescript/src/types/CactusSTTModel.d.ts +0 -8
  86. package/lib/typescript/src/types/CactusSTTModel.d.ts.map +0 -1
  87. package/src/types/CactusModel.ts +0 -15
  88. package/src/types/CactusSTTModel.ts +0 -10
@@ -13,12 +13,12 @@ import type {
13
13
  CactusLMImageEmbedResult,
14
14
  CactusLMParams,
15
15
  } from '../types/CactusLM';
16
- import type { CactusModel } from '../types/CactusModel';
17
16
  import { Telemetry } from '../telemetry/Telemetry';
18
17
  import { CactusConfig } from '../config/CactusConfig';
19
- import { Database } from '../api/Database';
20
18
  import { getErrorMessage } from '../utils/error';
21
19
  import { RemoteLM } from '../api/RemoteLM';
20
+ import models from '../models';
21
+ import type { CactusModel } from '../types/common';
22
22
 
23
23
  export class CactusLM {
24
24
  private readonly cactus = new Cactus();
@@ -26,25 +26,46 @@ export class CactusLM {
26
26
  private readonly model: string;
27
27
  private readonly contextSize: number;
28
28
  private readonly corpusDir?: string;
29
+ private readonly options: {
30
+ quantization: 'int4' | 'int8';
31
+ pro: boolean;
32
+ };
29
33
 
30
34
  private isDownloading = false;
31
35
  private isInitialized = false;
32
36
  private isGenerating = false;
33
37
 
34
- private static readonly defaultModel = 'qwen3-0.6';
38
+ private static readonly defaultModel = 'qwen3-0.6b';
35
39
  private static readonly defaultContextSize = 2048;
40
+ private static readonly defaultOptions = {
41
+ quantization: 'int4' as const,
42
+ pro: false,
43
+ };
44
+ private static readonly quantizationExceptions: {
45
+ [model: string]: 'int4' | 'int8';
46
+ } = {
47
+ 'gemma-3-270m-it': 'int8' as const,
48
+ 'functiongemma-270m-it': 'int8' as const,
49
+ };
36
50
  private static readonly defaultCompleteOptions = {
37
51
  maxTokens: 512,
38
52
  };
39
53
  private static readonly defaultCompleteMode = 'local';
40
54
  private static readonly defaultEmbedBufferSize = 2048;
41
55
 
42
- constructor({ model, contextSize, corpusDir }: CactusLMParams = {}) {
56
+ constructor({ model, contextSize, corpusDir, options }: CactusLMParams = {}) {
43
57
  Telemetry.init(CactusConfig.telemetryToken);
44
58
 
45
59
  this.model = model ?? CactusLM.defaultModel;
46
60
  this.contextSize = contextSize ?? CactusLM.defaultContextSize;
47
61
  this.corpusDir = corpusDir;
62
+ this.options = {
63
+ quantization:
64
+ options?.quantization ??
65
+ CactusLM.quantizationExceptions[this.model] ??
66
+ CactusLM.defaultOptions.quantization,
67
+ pro: options?.pro ?? CactusLM.defaultOptions.pro,
68
+ };
48
69
  }
49
70
 
50
71
  public async download({
@@ -59,17 +80,25 @@ export class CactusLM {
59
80
  throw new Error('CactusLM is already downloading');
60
81
  }
61
82
 
62
- if (await CactusFileSystem.modelExists(this.model)) {
83
+ if (await CactusFileSystem.modelExists(this.getModelName())) {
84
+ console.log('Model already exists', this.getModelName());
63
85
  onProgress?.(1.0);
64
86
  return;
65
87
  }
66
88
 
67
89
  this.isDownloading = true;
68
90
  try {
69
- const model = await Database.getModel(this.model);
91
+ const modelConfig =
92
+ models[this.model]?.quantization[this.options.quantization];
93
+ const url = this.options.pro ? modelConfig?.pro?.apple : modelConfig?.url;
94
+
95
+ if (!url) {
96
+ throw new Error(`Model ${this.model} with specified options not found`);
97
+ }
98
+
70
99
  await CactusFileSystem.downloadModel(
71
- this.model,
72
- model.downloadUrl,
100
+ this.getModelName(),
101
+ url,
73
102
  onProgress
74
103
  );
75
104
  } finally {
@@ -86,10 +115,13 @@ export class CactusLM {
86
115
  if (this.isModelPath(this.model)) {
87
116
  modelPath = this.model.replace('file://', '');
88
117
  } else {
89
- if (!(await CactusFileSystem.modelExists(this.model))) {
90
- throw new Error(`Model "${this.model}" is not downloaded`);
118
+ if (!(await CactusFileSystem.modelExists(this.getModelName()))) {
119
+ console.log('Model not found:', this.getModelName());
120
+ throw new Error(
121
+ `Model "${this.model}" with options ${JSON.stringify(this.options)} is not downloaded`
122
+ );
91
123
  }
92
- modelPath = await CactusFileSystem.getModelPath(this.model);
124
+ modelPath = await CactusFileSystem.getModelPath(this.getModelName());
93
125
  }
94
126
 
95
127
  try {
@@ -255,15 +287,15 @@ export class CactusLM {
255
287
  this.isInitialized = false;
256
288
  }
257
289
 
258
- public async getModels(): Promise<CactusModel[]> {
259
- const models = await Database.getModels();
260
- for (const model of models) {
261
- model.isDownloaded = await CactusFileSystem.modelExists(model.slug);
262
- }
263
- return models;
290
+ public getModels(): CactusModel[] {
291
+ return Object.values(models).filter((model) => model.completion);
264
292
  }
265
293
 
266
294
  private isModelPath(model: string): boolean {
267
295
  return model.startsWith('file://') || model.startsWith('/');
268
296
  }
297
+
298
+ private getModelName(): string {
299
+ return `${this.model}-${this.options.quantization}${this.options.pro ? '-pro' : ''}`;
300
+ }
269
301
  }
@@ -6,37 +6,56 @@ import type {
6
6
  CactusSTTParams,
7
7
  CactusSTTAudioEmbedParams,
8
8
  CactusSTTAudioEmbedResult,
9
+ CactusSTTStreamTranscribeInsertParams,
10
+ CactusSTTStreamTranscribeProcessParams,
11
+ CactusSTTStreamTranscribeProcessResult,
12
+ CactusSTTStreamTranscribeFinalizeResult,
9
13
  } from '../types/CactusSTT';
10
14
  import { Telemetry } from '../telemetry/Telemetry';
11
15
  import { CactusConfig } from '../config/CactusConfig';
12
- import { Database } from '../api/Database';
13
16
  import { getErrorMessage } from '../utils/error';
14
- import type { CactusSTTModel } from '../types/CactusSTTModel';
17
+ import models from '../models';
18
+ import type { CactusModel } from '../types/common';
15
19
 
16
20
  export class CactusSTT {
17
21
  private readonly cactus = new Cactus();
18
22
 
19
23
  private readonly model: string;
20
24
  private readonly contextSize: number;
25
+ private readonly options: {
26
+ quantization: 'int4' | 'int8';
27
+ pro: boolean;
28
+ };
21
29
 
22
30
  private isDownloading = false;
23
31
  private isInitialized = false;
24
32
  private isGenerating = false;
25
33
 
34
+ private isStreamTranscribeInitialized = false;
35
+
26
36
  private static readonly defaultModel = 'whisper-small';
27
37
  private static readonly defaultContextSize = 2048;
38
+ private static readonly defaultOptions = {
39
+ quantization: 'int4' as const,
40
+ pro: false,
41
+ };
28
42
  private static readonly defaultPrompt =
29
43
  '<|startoftranscript|><|en|><|transcribe|><|notimestamps|>';
30
44
  private static readonly defaultTranscribeOptions = {
31
- maxTokens: 512,
45
+ maxTokens: 384,
32
46
  };
33
47
  private static readonly defaultEmbedBufferSize = 4096;
34
48
 
35
- constructor({ model, contextSize }: CactusSTTParams = {}) {
49
+ constructor({ model, contextSize, options }: CactusSTTParams = {}) {
36
50
  Telemetry.init(CactusConfig.telemetryToken);
37
51
 
38
52
  this.model = model ?? CactusSTT.defaultModel;
39
53
  this.contextSize = contextSize ?? CactusSTT.defaultContextSize;
54
+ this.options = {
55
+ quantization:
56
+ options?.quantization ?? CactusSTT.defaultOptions.quantization,
57
+ pro: options?.pro ?? CactusSTT.defaultOptions.pro,
58
+ };
40
59
  }
41
60
 
42
61
  public async download({
@@ -51,17 +70,25 @@ export class CactusSTT {
51
70
  throw new Error('CactusSTT is already downloading');
52
71
  }
53
72
 
54
- if (await CactusFileSystem.modelExists(this.model)) {
73
+ if (await CactusFileSystem.modelExists(this.getModelName())) {
74
+ console.log('Model already exists', this.getModelName());
55
75
  onProgress?.(1.0);
56
76
  return;
57
77
  }
58
78
 
59
79
  this.isDownloading = true;
60
80
  try {
61
- const model = await Database.getSTTModel(this.model);
81
+ const modelConfig =
82
+ models[this.model]?.quantization[this.options.quantization];
83
+ const url = this.options.pro ? modelConfig?.pro?.apple : modelConfig?.url;
84
+
85
+ if (!url) {
86
+ throw new Error(`Model ${this.model} with specified options not found`);
87
+ }
88
+
62
89
  await CactusFileSystem.downloadModel(
63
- this.model,
64
- model.downloadUrl,
90
+ this.getModelName(),
91
+ url,
65
92
  onProgress
66
93
  );
67
94
  } finally {
@@ -78,10 +105,13 @@ export class CactusSTT {
78
105
  if (this.isModelPath(this.model)) {
79
106
  modelPath = this.model.replace('file://', '');
80
107
  } else {
81
- if (!(await CactusFileSystem.modelExists(this.model))) {
82
- throw new Error(`Model "${this.model}" is not downloaded`);
108
+ if (!(await CactusFileSystem.modelExists(this.getModelName()))) {
109
+ console.log('Model does not exist', this.getModelName());
110
+ throw new Error(
111
+ `Model "${this.model}" with options ${JSON.stringify(this.options)} is not downloaded`
112
+ );
83
113
  }
84
- modelPath = await CactusFileSystem.getModelPath(this.model);
114
+ modelPath = await CactusFileSystem.getModelPath(this.getModelName());
85
115
  }
86
116
 
87
117
  try {
@@ -137,6 +167,76 @@ export class CactusSTT {
137
167
  }
138
168
  }
139
169
 
170
+ public async streamTranscribeInit(): Promise<void> {
171
+ if (this.isStreamTranscribeInitialized) {
172
+ return;
173
+ }
174
+
175
+ await this.init();
176
+
177
+ try {
178
+ await this.cactus.streamTranscribeInit();
179
+ this.isStreamTranscribeInitialized = true;
180
+ } catch (error) {
181
+ throw error;
182
+ }
183
+ }
184
+
185
+ public async streamTranscribeInsert({
186
+ audio,
187
+ }: CactusSTTStreamTranscribeInsertParams): Promise<void> {
188
+ if (!this.isStreamTranscribeInitialized) {
189
+ throw new Error('CactusSTT stream transcribe is not initialized');
190
+ }
191
+
192
+ try {
193
+ await this.cactus.streamTranscribeInsert(audio);
194
+ } catch (error) {
195
+ throw error;
196
+ }
197
+ }
198
+
199
+ public async streamTranscribeProcess({
200
+ options,
201
+ }: CactusSTTStreamTranscribeProcessParams = {}): Promise<CactusSTTStreamTranscribeProcessResult> {
202
+ if (!this.isStreamTranscribeInitialized) {
203
+ throw new Error('CactusSTT stream transcribe is not initialized');
204
+ }
205
+
206
+ try {
207
+ const result = await this.cactus.streamTranscribeProcess(options);
208
+ return result;
209
+ } catch (error) {
210
+ throw error;
211
+ }
212
+ }
213
+
214
+ public async streamTranscribeFinalize(): Promise<CactusSTTStreamTranscribeFinalizeResult> {
215
+ if (!this.isStreamTranscribeInitialized) {
216
+ throw new Error('CactusSTT stream transcribe is not initialized');
217
+ }
218
+
219
+ try {
220
+ const result = await this.cactus.streamTranscribeFinalize();
221
+ return result;
222
+ } catch (error) {
223
+ throw error;
224
+ }
225
+ }
226
+
227
+ public async streamTranscribeDestroy(): Promise<void> {
228
+ if (!this.isStreamTranscribeInitialized) {
229
+ return;
230
+ }
231
+
232
+ try {
233
+ await this.cactus.streamTranscribeDestroy();
234
+ this.isStreamTranscribeInitialized = false;
235
+ } catch (error) {
236
+ throw error;
237
+ }
238
+ }
239
+
140
240
  public async audioEmbed({
141
241
  audioPath,
142
242
  }: CactusSTTAudioEmbedParams): Promise<CactusSTTAudioEmbedResult> {
@@ -177,20 +277,21 @@ export class CactusSTT {
177
277
  }
178
278
 
179
279
  await this.stop();
280
+ await this.streamTranscribeDestroy();
180
281
  await this.cactus.destroy();
181
282
 
182
283
  this.isInitialized = false;
183
284
  }
184
285
 
185
- public async getModels(): Promise<CactusSTTModel[]> {
186
- const models = await Database.getSTTModels();
187
- for (const model of models) {
188
- model.isDownloaded = await CactusFileSystem.modelExists(model.slug);
189
- }
190
- return models;
286
+ public getModels(): CactusModel[] {
287
+ return Object.values(models).filter((model) => model.speech);
191
288
  }
192
289
 
193
290
  private isModelPath(model: string): boolean {
194
291
  return model.startsWith('file://') || model.startsWith('/');
195
292
  }
293
+
294
+ private getModelName(): string {
295
+ return `${this.model}-${this.options.quantization}${this.options.pro ? '-pro' : ''}`;
296
+ }
196
297
  }
@@ -16,15 +16,19 @@ import type {
16
16
  CactusLMImageEmbedResult,
17
17
  CactusLMDownloadParams,
18
18
  } from '../types/CactusLM';
19
- import type { CactusModel } from '../types/CactusModel';
19
+ import type { CactusModel } from '../types/common';
20
20
 
21
21
  export const useCactusLM = ({
22
- model = 'qwen3-0.6',
22
+ model = 'qwen3-0.6b',
23
23
  contextSize = 2048,
24
24
  corpusDir = undefined,
25
+ options: modelOptions = {
26
+ quantization: undefined,
27
+ pro: false,
28
+ },
25
29
  }: CactusLMParams = {}) => {
26
30
  const [cactusLM, setCactusLM] = useState(
27
- () => new CactusLM({ model, contextSize, corpusDir })
31
+ () => new CactusLM({ model, contextSize, corpusDir, options: modelOptions })
28
32
  );
29
33
 
30
34
  // State
@@ -44,7 +48,17 @@ export const useCactusLM = ({
44
48
  }, [model]);
45
49
 
46
50
  useEffect(() => {
47
- setCactusLM(new CactusLM({ model, contextSize, corpusDir }));
51
+ setCactusLM(
52
+ new CactusLM({
53
+ model,
54
+ contextSize,
55
+ corpusDir,
56
+ options: {
57
+ quantization: modelOptions.quantization,
58
+ pro: modelOptions.pro,
59
+ },
60
+ })
61
+ );
48
62
 
49
63
  setCompletion('');
50
64
  setIsGenerating(false);
@@ -73,7 +87,13 @@ export const useCactusLM = ({
73
87
  return () => {
74
88
  mounted = false;
75
89
  };
76
- }, [model, contextSize, corpusDir]);
90
+ }, [
91
+ model,
92
+ contextSize,
93
+ corpusDir,
94
+ modelOptions.quantization,
95
+ modelOptions.pro,
96
+ ]);
77
97
 
78
98
  useEffect(() => {
79
99
  return () => {
@@ -9,20 +9,32 @@ import type {
9
9
  CactusSTTDownloadParams,
10
10
  CactusSTTAudioEmbedParams,
11
11
  CactusSTTAudioEmbedResult,
12
+ CactusSTTStreamTranscribeInsertParams,
13
+ CactusSTTStreamTranscribeProcessParams,
14
+ CactusSTTStreamTranscribeProcessResult,
15
+ CactusSTTStreamTranscribeFinalizeResult,
12
16
  } from '../types/CactusSTT';
13
- import type { CactusSTTModel } from '../types/CactusSTTModel';
17
+ import type { CactusModel } from '../types/common';
14
18
 
15
19
  export const useCactusSTT = ({
16
20
  model = 'whisper-small',
17
21
  contextSize = 2048,
22
+ options: modelOptions = {
23
+ quantization: undefined,
24
+ pro: false,
25
+ },
18
26
  }: CactusSTTParams = {}) => {
19
27
  const [cactusSTT, setCactusSTT] = useState(
20
- () => new CactusSTT({ model, contextSize })
28
+ () => new CactusSTT({ model, contextSize, options: modelOptions })
21
29
  );
22
30
 
23
31
  // State
24
32
  const [transcription, setTranscription] = useState('');
33
+ const [streamTranscribeConfirmed, setStreamTranscribeConfirmed] =
34
+ useState('');
35
+ const [streamTranscribePending, setStreamTranscribePending] = useState('');
25
36
  const [isGenerating, setIsGenerating] = useState(false);
37
+ const [isStreamTranscribing, setIsStreamTranscribing] = useState(false);
26
38
  const [isInitializing, setIsInitializing] = useState(false);
27
39
  const [isDownloaded, setIsDownloaded] = useState(false);
28
40
  const [isDownloading, setIsDownloading] = useState(false);
@@ -37,10 +49,22 @@ export const useCactusSTT = ({
37
49
  }, [model]);
38
50
 
39
51
  useEffect(() => {
40
- setCactusSTT(new CactusSTT({ model, contextSize }));
52
+ setCactusSTT(
53
+ new CactusSTT({
54
+ model,
55
+ contextSize,
56
+ options: {
57
+ quantization: modelOptions.quantization,
58
+ pro: modelOptions.pro,
59
+ },
60
+ })
61
+ );
41
62
 
42
63
  setTranscription('');
64
+ setStreamTranscribeConfirmed('');
65
+ setStreamTranscribePending('');
43
66
  setIsGenerating(false);
67
+ setIsStreamTranscribing(false);
44
68
  setIsInitializing(false);
45
69
  setIsDownloaded(false);
46
70
  setIsDownloading(false);
@@ -66,7 +90,7 @@ export const useCactusSTT = ({
66
90
  return () => {
67
91
  mounted = false;
68
92
  };
69
- }, [model, contextSize]);
93
+ }, [model, contextSize, modelOptions.quantization, modelOptions.pro]);
70
94
 
71
95
  useEffect(() => {
72
96
  return () => {
@@ -220,6 +244,83 @@ export const useCactusSTT = ({
220
244
  [cactusSTT, isGenerating]
221
245
  );
222
246
 
247
+ const streamTranscribeInit = useCallback(async () => {
248
+ if (isStreamTranscribing) {
249
+ return;
250
+ }
251
+
252
+ setError(null);
253
+ setStreamTranscribeConfirmed('');
254
+ setStreamTranscribePending('');
255
+ setIsStreamTranscribing(true);
256
+ try {
257
+ await cactusSTT.streamTranscribeInit();
258
+ } catch (e) {
259
+ setError(getErrorMessage(e));
260
+ setIsStreamTranscribing(false);
261
+ throw e;
262
+ }
263
+ }, [cactusSTT, isStreamTranscribing]);
264
+
265
+ const streamTranscribeInsert = useCallback(
266
+ async ({ audio }: CactusSTTStreamTranscribeInsertParams): Promise<void> => {
267
+ setError(null);
268
+ try {
269
+ await cactusSTT.streamTranscribeInsert({ audio });
270
+ } catch (e) {
271
+ setError(getErrorMessage(e));
272
+ throw e;
273
+ }
274
+ },
275
+ [cactusSTT]
276
+ );
277
+
278
+ const streamTranscribeProcess = useCallback(
279
+ async ({
280
+ options,
281
+ }: CactusSTTStreamTranscribeProcessParams = {}): Promise<CactusSTTStreamTranscribeProcessResult> => {
282
+ setError(null);
283
+ try {
284
+ const result = await cactusSTT.streamTranscribeProcess({ options });
285
+ setStreamTranscribeConfirmed((prev) => prev + result.confirmed);
286
+ setStreamTranscribePending(result.pending);
287
+ return result;
288
+ } catch (e) {
289
+ setError(getErrorMessage(e));
290
+ throw e;
291
+ }
292
+ },
293
+ [cactusSTT]
294
+ );
295
+
296
+ const streamTranscribeFinalize =
297
+ useCallback(async (): Promise<CactusSTTStreamTranscribeFinalizeResult> => {
298
+ setError(null);
299
+ try {
300
+ const result = await cactusSTT.streamTranscribeFinalize();
301
+ setStreamTranscribeConfirmed((prev) => prev + result.confirmed);
302
+ setStreamTranscribePending('');
303
+ setIsStreamTranscribing(false);
304
+ return result;
305
+ } catch (e) {
306
+ setError(getErrorMessage(e));
307
+ throw e;
308
+ }
309
+ }, [cactusSTT]);
310
+
311
+ const streamTranscribeDestroy = useCallback(async (): Promise<void> => {
312
+ setError(null);
313
+ try {
314
+ await cactusSTT.streamTranscribeDestroy();
315
+ } catch (e) {
316
+ setError(getErrorMessage(e));
317
+ throw e;
318
+ } finally {
319
+ setIsStreamTranscribing(false);
320
+ setStreamTranscribePending('');
321
+ }
322
+ }, [cactusSTT]);
323
+
223
324
  const stop = useCallback(async () => {
224
325
  setError(null);
225
326
  try {
@@ -251,10 +352,13 @@ export const useCactusSTT = ({
251
352
  throw e;
252
353
  } finally {
253
354
  setTranscription('');
355
+ setStreamTranscribeConfirmed('');
356
+ setStreamTranscribePending('');
357
+ setIsStreamTranscribing(false);
254
358
  }
255
359
  }, [cactusSTT]);
256
360
 
257
- const getModels = useCallback(async (): Promise<CactusSTTModel[]> => {
361
+ const getModels = useCallback(async (): Promise<CactusModel[]> => {
258
362
  setError(null);
259
363
  try {
260
364
  return await cactusSTT.getModels();
@@ -266,7 +370,10 @@ export const useCactusSTT = ({
266
370
 
267
371
  return {
268
372
  transcription,
373
+ streamTranscribeConfirmed,
374
+ streamTranscribePending,
269
375
  isGenerating,
376
+ isStreamTranscribing,
270
377
  isInitializing,
271
378
  isDownloaded,
272
379
  isDownloading,
@@ -277,6 +384,11 @@ export const useCactusSTT = ({
277
384
  init,
278
385
  transcribe,
279
386
  audioEmbed,
387
+ streamTranscribeInit,
388
+ streamTranscribeInsert,
389
+ streamTranscribeProcess,
390
+ streamTranscribeFinalize,
391
+ streamTranscribeDestroy,
280
392
  reset,
281
393
  stop,
282
394
  destroy,
package/src/index.tsx CHANGED
@@ -9,8 +9,7 @@ export { useCactusSTT } from './hooks/useCactusSTT';
9
9
  export { useCactusIndex } from './hooks/useCactusIndex';
10
10
 
11
11
  // Types
12
- export type { CactusModel } from './types/CactusModel';
13
- export type { CactusSTTModel } from './types/CactusSTTModel';
12
+ export type { CactusModel, ModelOptions } from './types/common';
14
13
  export type {
15
14
  CactusLMParams,
16
15
  CactusLMDownloadParams,
@@ -36,6 +35,11 @@ export type {
36
35
  CactusSTTTranscribeResult,
37
36
  CactusSTTAudioEmbedParams,
38
37
  CactusSTTAudioEmbedResult,
38
+ CactusSTTStreamTranscribeInsertParams,
39
+ StreamTranscribeProcessOptions,
40
+ CactusSTTStreamTranscribeProcessParams,
41
+ CactusSTTStreamTranscribeProcessResult,
42
+ CactusSTTStreamTranscribeFinalizeResult,
39
43
  } from './types/CactusSTT';
40
44
  export type {
41
45
  CactusIndexParams,