@charivo/stt-core 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Zeikar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,463 @@
1
+ # @charivo/stt-core
2
+
3
+ Core STT (Speech-to-Text) functionality with transcription coordination, event emission, and shared utilities for Charivo.
4
+
5
+ ## Features
6
+
7
+ - 🎤 **Transcription Coordination** - Manages STT transcribers with unified API
8
+ - 📡 **Event Bus Integration** - Emit audio events for recording lifecycle
9
+ - 🛠️ **MediaRecorder Helper** - Shared audio recording utility for transcribers
10
+ - 🔌 **Transcriber Agnostic** - Works with any STT transcriber (Web, OpenAI, Remote, etc.)
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pnpm add @charivo/stt-core @charivo/core
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### Basic Setup
21
+
22
+ ```typescript
23
+ import { createSTTManager } from "@charivo/stt-core";
24
+ import { createRemoteSTTTranscriber } from "@charivo/stt-transcriber-remote";
25
+
26
+ // Create a STT transcriber
27
+ const transcriber = createRemoteSTTTranscriber({
28
+ apiEndpoint: "/api/stt"
29
+ });
30
+
31
+ // Wrap with STTManager for event emission and coordination
32
+ const sttManager = createSTTManager(transcriber);
33
+
34
+ // Start recording (handled internally by transcriber)
35
+ await sttManager.start();
36
+
37
+ // Stop recording and get transcription
38
+ const transcription = await sttManager.stop();
39
+ console.log("User said:", transcription);
40
+ ```
41
+
42
+ ### With Event Bus
43
+
44
+ ```typescript
45
+ import { EventBus } from "@charivo/core";
46
+
47
+ const eventBus = new EventBus();
48
+ const sttManager = createSTTManager(transcriber);
49
+
50
+ // Connect event bus
51
+ sttManager.setEventEmitter({
52
+ emit: (event, data) => eventBus.emit(event, data)
53
+ });
54
+
55
+ // Listen to events
56
+ eventBus.on("stt:start", (data) => {
57
+ console.log("Recording started", data);
58
+ });
59
+
60
+ eventBus.on("stt:stop", (data) => {
61
+ console.log("Transcription:", data.transcription);
62
+ });
63
+
64
+ eventBus.on("stt:error", (data) => {
65
+ console.error("STT error:", data.error);
66
+ });
67
+
68
+ // Start recording
69
+ await sttManager.start();
70
+ // → "stt:start" emitted
71
+
72
+ // Stop and transcribe
73
+ const text = await sttManager.stop();
74
+ // → Recording stops (handled by transcriber)
75
+ // → Audio is transcribed
76
+ // → "stt:stop" emitted with transcription
77
+ ```
78
+
79
+ ### Custom STT Transcriber
80
+
81
+ Each transcriber handles recording internally:
82
+
83
+ ```typescript
84
+ import { STTTranscriber, STTOptions } from "@charivo/core";
85
+ import { MediaRecorderHelper, createSTTManager } from "@charivo/stt-core";
86
+
87
+ class MyCustomSTTTranscriber implements STTTranscriber {
88
+ private recorder = new MediaRecorderHelper();
89
+ private recordingOptions?: STTOptions;
90
+
91
+ async startRecording(options?: STTOptions): Promise<void> {
92
+ this.recordingOptions = options;
93
+ await this.recorder.start();
94
+ }
95
+
96
+ async stopRecording(): Promise<string> {
97
+ const audioBlob = await this.recorder.stop();
98
+
99
+ // Call your STT API
100
+ const formData = new FormData();
101
+ formData.append("audio", audioBlob);
102
+ if (this.recordingOptions?.language) {
103
+ formData.append("language", this.recordingOptions.language);
104
+ }
105
+
106
+ const response = await fetch("https://my-stt-api.com/transcribe", {
107
+ method: "POST",
108
+ body: formData
109
+ });
110
+
111
+ const data = await response.json();
112
+ this.recordingOptions = undefined;
113
+ return data.transcription;
114
+ }
115
+
116
+ isRecording(): boolean {
117
+ return this.recorder.isRecording();
118
+ }
119
+ }
120
+
121
+ const sttManager = createSTTManager(new MyCustomSTTTranscriber());
122
+ ```
123
+
124
+ ### Check Recording State
125
+
126
+ ```typescript
127
+ // Check if currently recording
128
+ if (sttManager.isRecording()) {
129
+ console.log("Recording in progress...");
130
+ } else {
131
+ console.log("Not recording");
132
+ }
133
+ ```
134
+
135
+ ## API Reference
136
+
137
+ ### `STTManager`
138
+
139
+ Main class for coordinating STT transcription and emitting events.
140
+
141
+ #### Constructor
142
+
143
+ ```typescript
144
+ new STTManager(transcriber: STTTranscriber)
145
+ ```
146
+
147
+ #### Methods
148
+
149
+ ##### `setEventEmitter(eventEmitter)`
150
+ Connect event emitter for STT event emission.
151
+
152
+ ```typescript
153
+ sttManager.setEventEmitter({
154
+ emit: (event, data) => { /* ... */ }
155
+ });
156
+ ```
157
+
158
+ When set, the manager emits:
159
+ - `stt:start` with `{ options?: STTOptions }` when recording starts
160
+ - `stt:stop` with `{ transcription: string }` when transcription completes
161
+ - `stt:error` with `{ error: Error }` when an error occurs
162
+
163
+ ##### `start(options?)`
164
+ Start audio recording (delegates to transcriber).
165
+
166
+ ```typescript
167
+ await sttManager.start();
168
+
169
+ // With language option
170
+ await sttManager.start({ language: "en-US" });
171
+ ```
172
+
173
+ The transcriber handles microphone access and recording internally.
174
+
175
+ ##### `stop()`
176
+ Stop recording and get transcribed text (delegates to transcriber).
177
+
178
+ ```typescript
179
+ const transcription = await sttManager.stop();
180
+ console.log("User said:", transcription);
181
+ ```
182
+
183
+ Returns the transcribed text as a string.
184
+
185
+ ##### `isRecording()`
186
+ Check if currently recording (delegates to transcriber).
187
+
188
+ ```typescript
189
+ if (sttManager.isRecording()) {
190
+ console.log("Recording...");
191
+ }
192
+ ```
193
+
194
+ ### `MediaRecorderHelper`
195
+
196
+ Shared utility for audio recording (used by blob-based transcribers).
197
+
198
+ #### Methods
199
+
200
+ ##### `start()`
201
+ Start audio recording from microphone.
202
+
203
+ ```typescript
204
+ const recorder = new MediaRecorderHelper();
205
+ await recorder.start();
206
+ ```
207
+
208
+ ##### `stop()`
209
+ Stop recording and return audio blob.
210
+
211
+ ```typescript
212
+ const audioBlob = await recorder.stop();
213
+ ```
214
+
215
+ ##### `isRecording()`
216
+ Check if currently recording.
217
+
218
+ ```typescript
219
+ if (recorder.isRecording()) {
220
+ console.log("Recording...");
221
+ }
222
+ ```
223
+
224
+ ##### `abort()`
225
+ Abort recording immediately without returning data.
226
+
227
+ ```typescript
228
+ recorder.abort();
229
+ ```
230
+
231
+ ## Events
232
+
233
+ ### `stt:start`
234
+
235
+ Emitted when audio recording starts.
236
+
237
+ ```typescript
238
+ {
239
+ options?: STTOptions
240
+ }
241
+ ```
242
+
243
+ Use this to:
244
+ - Show "recording" indicator
245
+ - Disable other audio inputs
246
+ - Update UI state
247
+
248
+ ### `stt:stop`
249
+
250
+ Emitted when audio recording stops and transcription completes.
251
+
252
+ ```typescript
253
+ {
254
+ transcription: string
255
+ }
256
+ ```
257
+
258
+ Use this to:
259
+ - Display transcribed text
260
+ - Hide "recording" indicator
261
+ - Process user input
262
+
263
+ ### `stt:error`
264
+
265
+ Emitted when an error occurs during recording or transcription.
266
+
267
+ ```typescript
268
+ {
269
+ error: Error
270
+ }
271
+ ```
272
+
273
+ Use this to:
274
+ - Show error message to user
275
+ - Clean up UI state
276
+ - Retry logic
277
+
278
+ ## Integration with Charivo
279
+
280
+ The STT system integrates seamlessly with the Charivo framework:
281
+
282
+ ```typescript
283
+ import { Charivo } from "@charivo/core";
284
+ import { createSTTManager } from "@charivo/stt-core";
285
+ import { createWebSTTTranscriber } from "@charivo/stt-transcriber-web";
286
+
287
+ const charivo = new Charivo();
288
+
289
+ // Setup STT
290
+ const transcriber = createWebSTTTranscriber();
291
+ const sttManager = createSTTManager(transcriber);
292
+ charivo.attachSTT(sttManager);
293
+
294
+ // Start voice input
295
+ await sttManager.start();
296
+
297
+ // Stop and automatically send to character
298
+ const transcription = await sttManager.stop();
299
+ await charivo.userSay(transcription);
300
+ // → Character responds with voice and animation
301
+ ```
302
+
303
+ ## Architecture
304
+
305
+ ```
306
+ STTManager (coordination layer)
307
+ ├─ Event Emission
308
+ └─ STTTranscriber (handles recording internally)
309
+ ├─ WebSTTTranscriber
310
+ │ └─ Web Speech API (real-time)
311
+ ├─ OpenAISTTTranscriber
312
+ │ ├─ MediaRecorderHelper
313
+ │ └─ OpenAI Whisper API
314
+ └─ RemoteSTTTranscriber
315
+ ├─ MediaRecorderHelper
316
+ └─ Your Server API
317
+ ```
318
+
319
+ ## Available Transcribers
320
+
321
+ ### Web STT Transcriber (Free, Browser-native) ⭐ Recommended
322
+
323
+ ```bash
324
+ pnpm add @charivo/stt-transcriber-web
325
+ ```
326
+
327
+ ```typescript
328
+ import { createWebSTTTranscriber } from "@charivo/stt-transcriber-web";
329
+
330
+ const transcriber = createWebSTTTranscriber();
331
+ const sttManager = createSTTManager(transcriber);
332
+
333
+ // Works with STTManager!
334
+ await sttManager.start({ language: "en-US" });
335
+ const text = await sttManager.stop();
336
+ ```
337
+
338
+ Uses browser's built-in Web Speech API (no API key needed).
339
+
340
+ **Advantages:**
341
+ - 🆓 Completely free
342
+ - ⚡ Real-time recognition
343
+ - 🔒 No server required
344
+ - 🎯 Perfect for development and production
345
+
346
+ ### Remote STT Transcriber (Production-ready)
347
+
348
+ ```bash
349
+ pnpm add @charivo/stt-transcriber-remote
350
+ ```
351
+
352
+ ```typescript
353
+ import { createRemoteSTTTranscriber } from "@charivo/stt-transcriber-remote";
354
+
355
+ const transcriber = createRemoteSTTTranscriber({
356
+ apiEndpoint: "/api/stt" // Your server endpoint
357
+ });
358
+ ```
359
+
360
+ Calls your server API to keep credentials secure.
361
+
362
+ ### OpenAI STT Transcriber (Development/Testing Only)
363
+
364
+ ```bash
365
+ pnpm add @charivo/stt-transcriber-openai
366
+ ```
367
+
368
+ ```typescript
369
+ import { createOpenAISTTTranscriber } from "@charivo/stt-transcriber-openai";
370
+
371
+ const transcriber = createOpenAISTTTranscriber({
372
+ apiKey: "your-api-key", // ⚠️ Exposed on client
373
+ defaultLanguage: "en"
374
+ });
375
+ ```
376
+
377
+ ⚠️ **Warning**: API key is exposed on the client. Only use for development/testing.
378
+
379
+ ## Browser Compatibility
380
+
381
+ STT transcribers use different browser APIs:
382
+
383
+ **MediaRecorderHelper** (OpenAI/Remote):
384
+ - Chrome/Edge 49+
385
+ - Firefox 29+
386
+ - Safari 14.1+
387
+
388
+ **Web Speech API** (Web):
389
+ - Chrome/Edge (fully supported)
390
+ - Safari (limited support)
391
+ - Firefox (not supported)
392
+
393
+ ## Error Handling
394
+
395
+ ```typescript
396
+ try {
397
+ await sttManager.start();
398
+ const transcription = await sttManager.stop();
399
+ } catch (error) {
400
+ if (error.name === "NotAllowedError") {
401
+ console.error("Microphone permission denied");
402
+ } else if (error.name === "NotFoundError") {
403
+ console.error("No microphone found");
404
+ } else {
405
+ console.error("STT error:", error);
406
+ }
407
+ }
408
+ ```
409
+
410
+ Common errors:
411
+ - `NotAllowedError` - User denied microphone permission
412
+ - `NotFoundError` - No microphone device available
413
+ - `NotReadableError` - Microphone is already in use
414
+ - Network errors - Transcription API failed
415
+
416
+ ## Best Practices
417
+
418
+ 1. **Use Web STT for most cases**: Free, fast, and browser-native
419
+ 2. **Request permission early**: Test microphone access before starting recording
420
+ 3. **Show recording indicator**: Always show visual feedback when recording
421
+ 4. **Handle errors gracefully**: Provide clear error messages to users
422
+
423
+ ```typescript
424
+ // React example
425
+ function VoiceInput() {
426
+ const [recording, setRecording] = useState(false);
427
+ const [error, setError] = useState<string | null>(null);
428
+
429
+ const handleStart = async () => {
430
+ try {
431
+ setError(null);
432
+ await sttManager.start();
433
+ setRecording(true);
434
+ } catch (err) {
435
+ setError("Failed to start recording");
436
+ }
437
+ };
438
+
439
+ const handleStop = async () => {
440
+ try {
441
+ const text = await sttManager.stop();
442
+ setRecording(false);
443
+ onTranscription(text);
444
+ } catch (err) {
445
+ setError("Failed to transcribe");
446
+ setRecording(false);
447
+ }
448
+ };
449
+
450
+ return (
451
+ <div>
452
+ <button onClick={recording ? handleStop : handleStart}>
453
+ {recording ? "Stop" : "Start"} Recording
454
+ </button>
455
+ {error && <div className="error">{error}</div>}
456
+ </div>
457
+ );
458
+ }
459
+ ```
460
+
461
+ ## License
462
+
463
+ MIT
@@ -0,0 +1,70 @@
1
+ import { STTManager, STTTranscriber, STTOptions } from '@charivo/core';
2
+
3
+ /**
4
+ * STT Manager - Manages STT session state
5
+ *
6
+ * Simplified design: Delegates to STTTranscriber
7
+ * - STTTranscriber handles recording internally
8
+ * - Manager only handles event emission
9
+ * - Thin wrapper for consistent API
10
+ */
11
+ declare class STTManagerImpl implements STTManager {
12
+ private sttTranscriber;
13
+ private eventEmitter?;
14
+ constructor(sttTranscriber: STTTranscriber);
15
+ /**
16
+ * Set event emitter for STT events
17
+ */
18
+ setEventEmitter(eventEmitter: {
19
+ emit: (event: string, data: any) => void;
20
+ }): void;
21
+ /**
22
+ * Start audio recording (delegates to transcriber)
23
+ */
24
+ start(options?: STTOptions): Promise<void>;
25
+ /**
26
+ * Stop audio recording and get transcription (delegates to transcriber)
27
+ */
28
+ stop(): Promise<string>;
29
+ /**
30
+ * Check if currently recording (delegates to transcriber)
31
+ */
32
+ isRecording(): boolean;
33
+ }
34
+ /**
35
+ * Helper function to create STT Manager
36
+ */
37
+ declare function createSTTManager(sttTranscriber: STTTranscriber): STTManager;
38
+
39
+ /**
40
+ * MediaRecorderHelper - Browser audio recording utility
41
+ *
42
+ * Handles MediaRecorder lifecycle:
43
+ * - Start/stop recording
44
+ * - Audio chunk collection
45
+ * - Stream cleanup
46
+ * - Blob generation
47
+ */
48
+ declare class MediaRecorderHelper {
49
+ private mediaRecorder;
50
+ private audioChunks;
51
+ private recording;
52
+ /**
53
+ * Start audio recording from user's microphone
54
+ */
55
+ start(): Promise<void>;
56
+ /**
57
+ * Stop audio recording and return the recorded audio as a Blob
58
+ */
59
+ stop(): Promise<Blob>;
60
+ /**
61
+ * Check if currently recording
62
+ */
63
+ isRecording(): boolean;
64
+ /**
65
+ * Abort recording immediately without returning data
66
+ */
67
+ abort(): void;
68
+ }
69
+
70
+ export { MediaRecorderHelper, STTManagerImpl, createSTTManager };
@@ -0,0 +1,70 @@
1
+ import { STTManager, STTTranscriber, STTOptions } from '@charivo/core';
2
+
3
+ /**
4
+ * STT Manager - Manages STT session state
5
+ *
6
+ * Simplified design: Delegates to STTTranscriber
7
+ * - STTTranscriber handles recording internally
8
+ * - Manager only handles event emission
9
+ * - Thin wrapper for consistent API
10
+ */
11
+ declare class STTManagerImpl implements STTManager {
12
+ private sttTranscriber;
13
+ private eventEmitter?;
14
+ constructor(sttTranscriber: STTTranscriber);
15
+ /**
16
+ * Set event emitter for STT events
17
+ */
18
+ setEventEmitter(eventEmitter: {
19
+ emit: (event: string, data: any) => void;
20
+ }): void;
21
+ /**
22
+ * Start audio recording (delegates to transcriber)
23
+ */
24
+ start(options?: STTOptions): Promise<void>;
25
+ /**
26
+ * Stop audio recording and get transcription (delegates to transcriber)
27
+ */
28
+ stop(): Promise<string>;
29
+ /**
30
+ * Check if currently recording (delegates to transcriber)
31
+ */
32
+ isRecording(): boolean;
33
+ }
34
+ /**
35
+ * Helper function to create STT Manager
36
+ */
37
+ declare function createSTTManager(sttTranscriber: STTTranscriber): STTManager;
38
+
39
+ /**
40
+ * MediaRecorderHelper - Browser audio recording utility
41
+ *
42
+ * Handles MediaRecorder lifecycle:
43
+ * - Start/stop recording
44
+ * - Audio chunk collection
45
+ * - Stream cleanup
46
+ * - Blob generation
47
+ */
48
+ declare class MediaRecorderHelper {
49
+ private mediaRecorder;
50
+ private audioChunks;
51
+ private recording;
52
+ /**
53
+ * Start audio recording from user's microphone
54
+ */
55
+ start(): Promise<void>;
56
+ /**
57
+ * Stop audio recording and return the recorded audio as a Blob
58
+ */
59
+ stop(): Promise<Blob>;
60
+ /**
61
+ * Check if currently recording
62
+ */
63
+ isRecording(): boolean;
64
+ /**
65
+ * Abort recording immediately without returning data
66
+ */
67
+ abort(): void;
68
+ }
69
+
70
+ export { MediaRecorderHelper, STTManagerImpl, createSTTManager };
package/dist/index.js ADDED
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ MediaRecorderHelper: () => MediaRecorderHelper,
24
+ STTManagerImpl: () => STTManagerImpl,
25
+ createSTTManager: () => createSTTManager
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/stt-manager.ts
30
+ var STTManagerImpl = class {
31
+ sttTranscriber;
32
+ eventEmitter;
33
+ constructor(sttTranscriber) {
34
+ this.sttTranscriber = sttTranscriber;
35
+ }
36
+ /**
37
+ * Set event emitter for STT events
38
+ */
39
+ setEventEmitter(eventEmitter) {
40
+ console.log("\u{1F517} STT Manager: Event emitter connected");
41
+ this.eventEmitter = eventEmitter;
42
+ }
43
+ /**
44
+ * Start audio recording (delegates to transcriber)
45
+ */
46
+ async start(options) {
47
+ console.log("\u{1F3A4} STT Manager: Starting recording", options);
48
+ this.eventEmitter?.emit("stt:start", { options });
49
+ try {
50
+ await this.sttTranscriber.startRecording(options);
51
+ console.log("\u2705 STT Manager: Recording started");
52
+ } catch (error) {
53
+ console.error("\u274C STT Manager: Recording failed", error);
54
+ this.eventEmitter?.emit("stt:error", { error });
55
+ throw error;
56
+ }
57
+ }
58
+ /**
59
+ * Stop audio recording and get transcription (delegates to transcriber)
60
+ */
61
+ async stop() {
62
+ console.log("\u{1F6D1} STT Manager: Stopping recording");
63
+ try {
64
+ const transcription = await this.sttTranscriber.stopRecording();
65
+ console.log("\u2705 STT Manager: Transcription completed", transcription);
66
+ this.eventEmitter?.emit("stt:stop", { transcription });
67
+ return transcription;
68
+ } catch (error) {
69
+ console.error("\u274C STT Manager: Transcription failed", error);
70
+ this.eventEmitter?.emit("stt:error", { error });
71
+ throw error;
72
+ }
73
+ }
74
+ /**
75
+ * Check if currently recording (delegates to transcriber)
76
+ */
77
+ isRecording() {
78
+ return this.sttTranscriber.isRecording();
79
+ }
80
+ };
81
+ function createSTTManager(sttTranscriber) {
82
+ return new STTManagerImpl(sttTranscriber);
83
+ }
84
+
85
+ // src/media-recorder-helper.ts
86
+ var MediaRecorderHelper = class {
87
+ mediaRecorder = null;
88
+ audioChunks = [];
89
+ recording = false;
90
+ /**
91
+ * Start audio recording from user's microphone
92
+ */
93
+ async start() {
94
+ if (this.recording) {
95
+ throw new Error("Already recording");
96
+ }
97
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
98
+ this.mediaRecorder = new MediaRecorder(stream);
99
+ this.audioChunks = [];
100
+ this.mediaRecorder.ondataavailable = (event) => {
101
+ if (event.data.size > 0) {
102
+ this.audioChunks.push(event.data);
103
+ }
104
+ };
105
+ this.mediaRecorder.start();
106
+ this.recording = true;
107
+ }
108
+ /**
109
+ * Stop audio recording and return the recorded audio as a Blob
110
+ */
111
+ async stop() {
112
+ if (!this.recording || !this.mediaRecorder) {
113
+ throw new Error("Not recording");
114
+ }
115
+ return new Promise((resolve, reject) => {
116
+ this.mediaRecorder.onstop = () => {
117
+ const audioBlob = new Blob(this.audioChunks, { type: "audio/webm" });
118
+ this.audioChunks = [];
119
+ this.mediaRecorder?.stream.getTracks().forEach((track) => track.stop());
120
+ this.mediaRecorder = null;
121
+ this.recording = false;
122
+ resolve(audioBlob);
123
+ };
124
+ this.mediaRecorder.onerror = (error) => {
125
+ this.recording = false;
126
+ reject(error);
127
+ };
128
+ this.mediaRecorder.stop();
129
+ });
130
+ }
131
+ /**
132
+ * Check if currently recording
133
+ */
134
+ isRecording() {
135
+ return this.recording;
136
+ }
137
+ /**
138
+ * Abort recording immediately without returning data
139
+ */
140
+ abort() {
141
+ if (this.mediaRecorder) {
142
+ this.mediaRecorder.stream.getTracks().forEach((track) => track.stop());
143
+ this.mediaRecorder = null;
144
+ this.audioChunks = [];
145
+ this.recording = false;
146
+ }
147
+ }
148
+ };
149
+ // Annotate the CommonJS export names for ESM import in node:
150
+ 0 && (module.exports = {
151
+ MediaRecorderHelper,
152
+ STTManagerImpl,
153
+ createSTTManager
154
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,125 @@
1
+ // src/stt-manager.ts
2
+ var STTManagerImpl = class {
3
+ sttTranscriber;
4
+ eventEmitter;
5
+ constructor(sttTranscriber) {
6
+ this.sttTranscriber = sttTranscriber;
7
+ }
8
+ /**
9
+ * Set event emitter for STT events
10
+ */
11
+ setEventEmitter(eventEmitter) {
12
+ console.log("\u{1F517} STT Manager: Event emitter connected");
13
+ this.eventEmitter = eventEmitter;
14
+ }
15
+ /**
16
+ * Start audio recording (delegates to transcriber)
17
+ */
18
+ async start(options) {
19
+ console.log("\u{1F3A4} STT Manager: Starting recording", options);
20
+ this.eventEmitter?.emit("stt:start", { options });
21
+ try {
22
+ await this.sttTranscriber.startRecording(options);
23
+ console.log("\u2705 STT Manager: Recording started");
24
+ } catch (error) {
25
+ console.error("\u274C STT Manager: Recording failed", error);
26
+ this.eventEmitter?.emit("stt:error", { error });
27
+ throw error;
28
+ }
29
+ }
30
+ /**
31
+ * Stop audio recording and get transcription (delegates to transcriber)
32
+ */
33
+ async stop() {
34
+ console.log("\u{1F6D1} STT Manager: Stopping recording");
35
+ try {
36
+ const transcription = await this.sttTranscriber.stopRecording();
37
+ console.log("\u2705 STT Manager: Transcription completed", transcription);
38
+ this.eventEmitter?.emit("stt:stop", { transcription });
39
+ return transcription;
40
+ } catch (error) {
41
+ console.error("\u274C STT Manager: Transcription failed", error);
42
+ this.eventEmitter?.emit("stt:error", { error });
43
+ throw error;
44
+ }
45
+ }
46
+ /**
47
+ * Check if currently recording (delegates to transcriber)
48
+ */
49
+ isRecording() {
50
+ return this.sttTranscriber.isRecording();
51
+ }
52
+ };
53
+ function createSTTManager(sttTranscriber) {
54
+ return new STTManagerImpl(sttTranscriber);
55
+ }
56
+
57
+ // src/media-recorder-helper.ts
58
+ var MediaRecorderHelper = class {
59
+ mediaRecorder = null;
60
+ audioChunks = [];
61
+ recording = false;
62
+ /**
63
+ * Start audio recording from user's microphone
64
+ */
65
+ async start() {
66
+ if (this.recording) {
67
+ throw new Error("Already recording");
68
+ }
69
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
70
+ this.mediaRecorder = new MediaRecorder(stream);
71
+ this.audioChunks = [];
72
+ this.mediaRecorder.ondataavailable = (event) => {
73
+ if (event.data.size > 0) {
74
+ this.audioChunks.push(event.data);
75
+ }
76
+ };
77
+ this.mediaRecorder.start();
78
+ this.recording = true;
79
+ }
80
+ /**
81
+ * Stop audio recording and return the recorded audio as a Blob
82
+ */
83
+ async stop() {
84
+ if (!this.recording || !this.mediaRecorder) {
85
+ throw new Error("Not recording");
86
+ }
87
+ return new Promise((resolve, reject) => {
88
+ this.mediaRecorder.onstop = () => {
89
+ const audioBlob = new Blob(this.audioChunks, { type: "audio/webm" });
90
+ this.audioChunks = [];
91
+ this.mediaRecorder?.stream.getTracks().forEach((track) => track.stop());
92
+ this.mediaRecorder = null;
93
+ this.recording = false;
94
+ resolve(audioBlob);
95
+ };
96
+ this.mediaRecorder.onerror = (error) => {
97
+ this.recording = false;
98
+ reject(error);
99
+ };
100
+ this.mediaRecorder.stop();
101
+ });
102
+ }
103
+ /**
104
+ * Check if currently recording
105
+ */
106
+ isRecording() {
107
+ return this.recording;
108
+ }
109
+ /**
110
+ * Abort recording immediately without returning data
111
+ */
112
+ abort() {
113
+ if (this.mediaRecorder) {
114
+ this.mediaRecorder.stream.getTracks().forEach((track) => track.stop());
115
+ this.mediaRecorder = null;
116
+ this.audioChunks = [];
117
+ this.recording = false;
118
+ }
119
+ }
120
+ };
121
+ export {
122
+ MediaRecorderHelper,
123
+ STTManagerImpl,
124
+ createSTTManager
125
+ };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@charivo/stt-core",
3
+ "version": "0.0.1",
4
+ "description": "Core STT functionality for Charivo framework",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "keywords": [
16
+ "charivo",
17
+ "stt",
18
+ "speech-to-text",
19
+ "audio",
20
+ "transcription"
21
+ ],
22
+ "dependencies": {
23
+ "@charivo/core": "0.0.1"
24
+ },
25
+ "devDependencies": {
26
+ "@charivo/shared": "0.0.1"
27
+ },
28
+ "peerDependencies": {},
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/zeikar/charivo.git",
39
+ "directory": "packages/stt-core"
40
+ },
41
+ "author": {
42
+ "name": "Zeikar",
43
+ "url": "https://github.com/zeikar"
44
+ },
45
+ "homepage": "https://github.com/zeikar/charivo#readme",
46
+ "bugs": {
47
+ "url": "https://github.com/zeikar/charivo/issues"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "dev": "tsup --watch",
52
+ "test": "vitest",
53
+ "clean": "rm -rf dist"
54
+ }
55
+ }