@longline/aqua-ui 1.0.331 → 1.0.335

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 (44) hide show
  1. package/hooks/useSpeechAIRecorder/index.d.ts +1 -0
  2. package/hooks/useSpeechAIRecorder/index.js +1 -0
  3. package/hooks/useSpeechAIRecorder/stories/SpeechAIAudioInput.d.ts +6 -0
  4. package/hooks/{useAssemblyAIRecorder/stories/AssemblyAudioInput.js → useSpeechAIRecorder/stories/SpeechAIAudioInput.js} +4 -4
  5. package/hooks/useSpeechAIRecorder/useSpeechAIRecorder.d.ts +29 -0
  6. package/hooks/{useAssemblyAIRecorder/useAssemblyAIRecorder.js → useSpeechAIRecorder/useSpeechAIRecorder.js} +13 -11
  7. package/hooks/useTextAIStream/index.d.ts +1 -0
  8. package/hooks/useTextAIStream/index.js +1 -0
  9. package/hooks/{useOpenAIStream/stories/OpenAIStreamInput.d.ts → useTextAIStream/stories/TextAIStreamInput.d.ts} +3 -3
  10. package/hooks/{useOpenAIStream/stories/OpenAIStreamInput.js → useTextAIStream/stories/TextAIStreamInput.js} +6 -6
  11. package/hooks/useTextAIStream/useTextAIStream.d.ts +26 -0
  12. package/hooks/{useOpenAIStream/useOpenAIStream.js → useTextAIStream/useTextAIStream.js} +16 -4
  13. package/inputs/DateInput/Selector.js +17 -10
  14. package/inputs/Editor/Editor.d.ts +7 -6
  15. package/inputs/Editor/Editor.js +1 -1
  16. package/inputs/Editor/buttons/{SpeechButton.d.ts → SpeechAIButton.d.ts} +2 -2
  17. package/inputs/Editor/buttons/{SpeechButton.js → SpeechAIButton.js} +5 -5
  18. package/inputs/Editor/buttons/TextAIButton.d.ts +28 -0
  19. package/inputs/Editor/buttons/{OpenAIButton.js → TextAIButton.js} +13 -14
  20. package/inputs/Editor/buttons/{OpenAIMenu.d.ts → TextAIMenu.d.ts} +2 -2
  21. package/inputs/Editor/buttons/{OpenAIMenu.js → TextAIMenu.js} +3 -3
  22. package/inputs/Editor/menu/MenuBar.d.ts +6 -6
  23. package/inputs/Editor/menu/MenuBar.js +7 -7
  24. package/package.json +4 -5
  25. package/hooks/useAssemblyAIRecorder/index.d.ts +0 -1
  26. package/hooks/useAssemblyAIRecorder/index.js +0 -1
  27. package/hooks/useAssemblyAIRecorder/stories/AssemblyAudioInput.d.ts +0 -6
  28. package/hooks/useAssemblyAIRecorder/useAssemblyAIRecorder.d.ts +0 -27
  29. package/hooks/useOpenAIRecorder/index.d.ts +0 -1
  30. package/hooks/useOpenAIRecorder/index.js +0 -1
  31. package/hooks/useOpenAIRecorder/old/AudioInputNoHook.d.ts +0 -8
  32. package/hooks/useOpenAIRecorder/old/AudioInputNoHook.js +0 -192
  33. package/hooks/useOpenAIRecorder/old/AudioInputStandardMedia.d.ts +0 -5
  34. package/hooks/useOpenAIRecorder/old/AudioInputStandardMedia.js +0 -170
  35. package/hooks/useOpenAIRecorder/stories/OpenAIAudioInput.d.ts +0 -8
  36. package/hooks/useOpenAIRecorder/stories/OpenAIAudioInput.js +0 -17
  37. package/hooks/useOpenAIRecorder/useOpenAIRecorder.d.ts +0 -22
  38. package/hooks/useOpenAIRecorder/useOpenAIRecorder.js +0 -223
  39. package/hooks/useOpenAIStream/index.d.ts +0 -1
  40. package/hooks/useOpenAIStream/index.js +0 -1
  41. package/hooks/useOpenAIStream/useOpenAIStream.d.ts +0 -14
  42. package/inputs/Editor/buttons/OpenAIButton.d.ts +0 -29
  43. /package/hooks/{useAssemblyAIRecorder → useSpeechAIRecorder}/SpeechManager.d.ts +0 -0
  44. /package/hooks/{useAssemblyAIRecorder → useSpeechAIRecorder}/SpeechManager.js +0 -0
@@ -1,192 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
- import * as React from 'react';
38
- import { MediaRecorder, register } from 'extendable-media-recorder';
39
- import { connect } from 'extendable-media-recorder-wav-encoder';
40
- import { Fab } from '../../../controls/Fab';
41
- import { SVG } from '../../../svg';
42
- /**
43
- * The extended media recorder allows converting to .wav format.
44
- */
45
- var AudioInput = function (props) {
46
- var _a = React.useState(false), isRecording = _a[0], setIsRecording = _a[1];
47
- var _b = React.useState(''), transcript = _b[0], setTranscript = _b[1];
48
- var mediaRecorderRef = React.useRef(null);
49
- var streamRef = React.useRef(null);
50
- var streamIdRef = React.useRef(Date.now().toString()); // Unique per session
51
- var sourceRef = React.useRef(null);
52
- var header;
53
- var startRecording = function () { return __awaiter(void 0, void 0, void 0, function () {
54
- var _a, _b, mediaRecorder, err_1;
55
- return __generator(this, function (_c) {
56
- switch (_c.label) {
57
- case 0:
58
- _c.trys.push([0, 4, , 5]);
59
- _a = register;
60
- return [4 /*yield*/, connect()];
61
- case 1: return [4 /*yield*/, _a.apply(void 0, [_c.sent()])];
62
- case 2:
63
- _c.sent();
64
- _b = streamRef;
65
- return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ audio: true })];
66
- case 3:
67
- _b.current = _c.sent();
68
- mediaRecorder = new MediaRecorder(streamRef.current, { mimeType: 'audio/wav' });
69
- mediaRecorder.ondataavailable = function (event) { return __awaiter(void 0, void 0, void 0, function () {
70
- var blob, formData, content, error_1;
71
- return __generator(this, function (_a) {
72
- switch (_a.label) {
73
- case 0:
74
- if (!(event.data.size > 0)) return [3 /*break*/, 8];
75
- blob = event.data;
76
- formData = new FormData();
77
- if (!(header === undefined)) return [3 /*break*/, 2];
78
- return [4 /*yield*/, blob.arrayBuffer()];
79
- case 1:
80
- header = (_a.sent()).slice(0, 44);
81
- return [3 /*break*/, 4];
82
- case 2: return [4 /*yield*/, blob.arrayBuffer()];
83
- case 3:
84
- content = _a.sent();
85
- blob = new Blob([header, content], { type: blob.type });
86
- _a.label = 4;
87
- case 4:
88
- formData.append('audio', blob);
89
- formData.append('stream_id', streamIdRef.current);
90
- _a.label = 5;
91
- case 5:
92
- _a.trys.push([5, 7, , 8]);
93
- return [4 /*yield*/, fetch('http://api.flow/api/ai/upload-audio-chunk', {
94
- method: 'POST',
95
- body: formData,
96
- })];
97
- case 6:
98
- _a.sent();
99
- return [3 /*break*/, 8];
100
- case 7:
101
- error_1 = _a.sent();
102
- console.error('Upload failed:', error_1);
103
- return [3 /*break*/, 8];
104
- case 8: return [2 /*return*/];
105
- }
106
- });
107
- }); };
108
- mediaRecorderRef.current = mediaRecorder;
109
- mediaRecorder.start(20000); // 4-second chunks
110
- return [3 /*break*/, 5];
111
- case 4:
112
- err_1 = _c.sent();
113
- console.error('Microphone access error:', err_1);
114
- setIsRecording(false);
115
- return [3 /*break*/, 5];
116
- case 5: return [2 /*return*/];
117
- }
118
- });
119
- }); };
120
- React.useEffect(function () {
121
- var _a, _b, _c;
122
- if (isRecording) {
123
- startRecording();
124
- }
125
- else {
126
- if (((_a = mediaRecorderRef.current) === null || _a === void 0 ? void 0 : _a.state) !== 'inactive') {
127
- (_b = mediaRecorderRef.current) === null || _b === void 0 ? void 0 : _b.stop();
128
- }
129
- (_c = streamRef.current) === null || _c === void 0 ? void 0 : _c.getTracks().forEach(function (track) { return track.stop(); });
130
- }
131
- ;
132
- }, [isRecording]);
133
- var readyStateToString = function (state) {
134
- switch (state) {
135
- case EventSource.CLOSED: return "CLOSED";
136
- case EventSource.OPEN: return "OPEN";
137
- case EventSource.CONNECTING: return "CONNECTING";
138
- default:
139
- return "UNKNOWN";
140
- }
141
- };
142
- var eventPhaseToString = function (phase) {
143
- switch (phase) {
144
- case Event.NONE: return "NONE";
145
- case Event.CAPTURING_PHASE: return "CAPTURING_PHASE";
146
- case Event.AT_TARGET: return "AT_TARGET";
147
- case Event.BUBBLING_PHASE: return "BUBBLING_PHASE";
148
- default:
149
- return "UNKNOWN";
150
- }
151
- };
152
- React.useEffect(function () {
153
- if (isRecording) {
154
- sourceRef.current = new EventSource("http://api.flow/api/ai/transcribe-stream/".concat(streamIdRef.current));
155
- sourceRef.current.onmessage = function (event) {
156
- console.log("Message:", event.data);
157
- console.log("ReadyState:", readyStateToString(sourceRef.current.readyState));
158
- setTranscript(function (prev) { return prev + event.data + '\n'; });
159
- };
160
- sourceRef.current.onerror = function (err) {
161
- console.error('SSE error:', err);
162
- console.log('EventPhase:', eventPhaseToString(err.eventPhase));
163
- console.log('ReadyState:', readyStateToString(sourceRef.current.readyState));
164
- sourceRef.current.close();
165
- };
166
- }
167
- return function () { var _a; return (_a = sourceRef.current) === null || _a === void 0 ? void 0 : _a.close(); };
168
- }, [isRecording]);
169
- var start = function () {
170
- setTranscript('');
171
- streamIdRef.current = Date.now().toString(); // Reset for new session
172
- setIsRecording(true);
173
- };
174
- var stop = function () {
175
- var _a;
176
- setIsRecording(false);
177
- if (((_a = mediaRecorderRef.current) === null || _a === void 0 ? void 0 : _a.state) !== 'inactive') {
178
- mediaRecorderRef.current.stop();
179
- }
180
- };
181
- var handleToggle = function () {
182
- if (isRecording) {
183
- stop();
184
- }
185
- else {
186
- start();
187
- }
188
- };
189
- return (React.createElement("div", null,
190
- React.createElement(Fab, { title: "Record", active: isRecording, icon: SVG.Icons.Microphone, onClick: handleToggle })));
191
- };
192
- export { AudioInput };
@@ -1,5 +0,0 @@
1
- import * as React from 'react';
2
- interface IProps {
3
- }
4
- declare const AudioInput: (props: IProps) => React.JSX.Element;
5
- export { AudioInput };
@@ -1,170 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
- import * as React from 'react';
38
- import { Fab } from '../../../controls/Fab';
39
- import { SVG } from '../../../svg';
40
- var AudioInput = function (props) {
41
- var _a = React.useState(false), isRecording = _a[0], setIsRecording = _a[1];
42
- var _b = React.useState(''), transcript = _b[0], setTranscript = _b[1];
43
- var mediaRecorderRef = React.useRef(null);
44
- var streamRef = React.useRef(null);
45
- var streamIdRef = React.useRef(Date.now().toString()); // Unique per session
46
- var sourceRef = React.useRef(null);
47
- var startRecording = function () { return __awaiter(void 0, void 0, void 0, function () {
48
- var _a, mediaRecorder, err_1;
49
- return __generator(this, function (_b) {
50
- switch (_b.label) {
51
- case 0:
52
- _b.trys.push([0, 2, , 3]);
53
- _a = streamRef;
54
- return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ audio: true })];
55
- case 1:
56
- _a.current = _b.sent();
57
- mediaRecorder = new MediaRecorder(streamRef.current, { mimeType: 'audio/webm' });
58
- mediaRecorder.ondataavailable = function (event) { return __awaiter(void 0, void 0, void 0, function () {
59
- var blob, formData, error_1;
60
- return __generator(this, function (_a) {
61
- switch (_a.label) {
62
- case 0:
63
- if (!(event.data.size > 0)) return [3 /*break*/, 4];
64
- blob = event.data;
65
- formData = new FormData();
66
- formData.append('audio', blob);
67
- formData.append('stream_id', streamIdRef.current);
68
- _a.label = 1;
69
- case 1:
70
- _a.trys.push([1, 3, , 4]);
71
- return [4 /*yield*/, fetch('http://api.flow/api/ai/upload-audio-chunk', {
72
- method: 'POST',
73
- body: formData,
74
- })];
75
- case 2:
76
- _a.sent();
77
- return [3 /*break*/, 4];
78
- case 3:
79
- error_1 = _a.sent();
80
- console.error('Upload failed:', error_1);
81
- return [3 /*break*/, 4];
82
- case 4: return [2 /*return*/];
83
- }
84
- });
85
- }); };
86
- mediaRecorderRef.current = mediaRecorder;
87
- mediaRecorder.start(1000); // 1-second chunks
88
- return [3 /*break*/, 3];
89
- case 2:
90
- err_1 = _b.sent();
91
- console.error('Microphone access error:', err_1);
92
- setIsRecording(false);
93
- return [3 /*break*/, 3];
94
- case 3: return [2 /*return*/];
95
- }
96
- });
97
- }); };
98
- React.useEffect(function () {
99
- var _a, _b, _c;
100
- if (isRecording) {
101
- startRecording();
102
- }
103
- else {
104
- if (((_a = mediaRecorderRef.current) === null || _a === void 0 ? void 0 : _a.state) !== 'inactive') {
105
- (_b = mediaRecorderRef.current) === null || _b === void 0 ? void 0 : _b.stop();
106
- }
107
- (_c = streamRef.current) === null || _c === void 0 ? void 0 : _c.getTracks().forEach(function (track) { return track.stop(); });
108
- }
109
- ;
110
- }, [isRecording]);
111
- var readyStateToString = function (state) {
112
- switch (state) {
113
- case EventSource.CLOSED: return "CLOSED";
114
- case EventSource.OPEN: return "OPEN";
115
- case EventSource.CONNECTING: return "CONNECTING";
116
- default:
117
- return "UNKNOWN";
118
- }
119
- };
120
- var eventPhaseToString = function (phase) {
121
- switch (phase) {
122
- case Event.NONE: return "NONE";
123
- case Event.CAPTURING_PHASE: return "CAPTURING_PHASE";
124
- case Event.AT_TARGET: return "AT_TARGET";
125
- case Event.BUBBLING_PHASE: return "BUBBLING_PHASE";
126
- default:
127
- return "UNKNOWN";
128
- }
129
- };
130
- React.useEffect(function () {
131
- if (isRecording) {
132
- sourceRef.current = new EventSource("http://api.flow/api/ai/transcribe-stream/".concat(streamIdRef.current));
133
- sourceRef.current.onmessage = function (event) {
134
- console.log("Message:", event.data);
135
- console.log("ReadyState:", readyStateToString(sourceRef.current.readyState));
136
- setTranscript(function (prev) { return prev + event.data + '\n'; });
137
- };
138
- sourceRef.current.onerror = function (err) {
139
- console.error('SSE error:', err);
140
- console.log('EventPhase:', eventPhaseToString(err.eventPhase));
141
- console.log('ReadyState:', readyStateToString(sourceRef.current.readyState));
142
- sourceRef.current.close();
143
- };
144
- }
145
- return function () { var _a; return (_a = sourceRef.current) === null || _a === void 0 ? void 0 : _a.close(); };
146
- }, [isRecording]);
147
- var start = function () {
148
- setTranscript('');
149
- streamIdRef.current = Date.now().toString(); // Reset for new session
150
- setIsRecording(true);
151
- };
152
- var stop = function () {
153
- var _a;
154
- setIsRecording(false);
155
- if (((_a = mediaRecorderRef.current) === null || _a === void 0 ? void 0 : _a.state) !== 'inactive') {
156
- mediaRecorderRef.current.stop();
157
- }
158
- };
159
- var handleToggle = function () {
160
- if (isRecording) {
161
- stop();
162
- }
163
- else {
164
- start();
165
- }
166
- };
167
- return (React.createElement("div", null,
168
- React.createElement(Fab, { title: "Record", active: isRecording, icon: SVG.Icons.Microphone, onClick: handleToggle })));
169
- };
170
- export { AudioInput };
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- interface IProps {
3
- audio_url: string;
4
- transcribe_url: string;
5
- interval: number;
6
- }
7
- declare const OpenAIAudioInput: (props: IProps) => React.JSX.Element;
8
- export { OpenAIAudioInput };
@@ -1,17 +0,0 @@
1
- import React, { useState } from 'react';
2
- import { useOpenAIRecorder } from '../useOpenAIRecorder';
3
- var OpenAIAudioInput = function (props) {
4
- var _a = useState('initial'), transcript = _a[0], setTranscript = _a[1];
5
- var _b = useOpenAIRecorder(props.audio_url, props.transcribe_url, props.interval, setTranscript), recordingStatus = _b.recordingStatus, toggleRecording = _b.toggleRecording;
6
- var getLabel = function (recordingStatus) {
7
- switch (recordingStatus) {
8
- case 'connecting': return "Connecting";
9
- case 'recording': return "Recording";
10
- default: return "Idle";
11
- }
12
- };
13
- return (React.createElement("div", null,
14
- React.createElement("button", { onClick: toggleRecording }, getLabel(recordingStatus)),
15
- React.createElement("p", { style: { border: 'solid 1px blue', minHeight: '200px', color: 'white' } }, transcript)));
16
- };
17
- export { OpenAIAudioInput };
@@ -1,22 +0,0 @@
1
- type TranscriptCallback = (text: string) => void;
2
- type TRecordingStatus = 'idle' | 'connecting' | 'recording';
3
- /**
4
- * useOpenAIRecorder
5
- *
6
- * Custom React hook for audio recording and transcription using:
7
- * - extendable-media-recorder with WAV encoder
8
- * - Server-Sent Events (SSE) for real-time transcript updates
9
- *
10
- * @param `audio_url` - Backend URL for audio chunks
11
- * @param `transcribe_url` - Backend URL for stream transcription
12
- * @param interval - Chunk length (in milliseconds)
13
- * @param onTranscript - Callback function called with the full running transcript
14
- * @returns An object containing:
15
- * - recordingStatus: current status of the recording lifecycle
16
- * - toggleRecording: function to start or stop recording
17
- */
18
- declare const useOpenAIRecorder: (audio_url: string, transcribe_url: string, interval: number, onTranscript: TranscriptCallback) => {
19
- recordingStatus: TRecordingStatus;
20
- toggleRecording: () => void;
21
- };
22
- export { useOpenAIRecorder, TRecordingStatus };
@@ -1,223 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
- import { useEffect, useRef, useState, useCallback } from 'react';
38
- import { MediaRecorder, register } from 'extendable-media-recorder';
39
- import { connect } from 'extendable-media-recorder-wav-encoder';
40
- /**
41
- * useOpenAIRecorder
42
- *
43
- * Custom React hook for audio recording and transcription using:
44
- * - extendable-media-recorder with WAV encoder
45
- * - Server-Sent Events (SSE) for real-time transcript updates
46
- *
47
- * @param `audio_url` - Backend URL for audio chunks
48
- * @param `transcribe_url` - Backend URL for stream transcription
49
- * @param interval - Chunk length (in milliseconds)
50
- * @param onTranscript - Callback function called with the full running transcript
51
- * @returns An object containing:
52
- * - recordingStatus: current status of the recording lifecycle
53
- * - toggleRecording: function to start or stop recording
54
- */
55
- var useOpenAIRecorder = function (audio_url, transcribe_url, interval, onTranscript) {
56
- // React state to track whether we are idle, connecting, or recording
57
- var _a = useState('idle'), recordingStatus = _a[0], setRecordingStatus = _a[1];
58
- // Stores the MediaRecorder instance (from extendable-media-recorder)
59
- var mediaRecorderRef = useRef(null);
60
- // Flag to ensure we register the WAV encoder only once per page lifetime
61
- var hasRegisteredEncoder = useRef(false);
62
- // The MediaStream from the user's microphone
63
- var streamRef = useRef(null);
64
- // A unique ID to identify this recording session (used in SSE + POST)
65
- var streamIdRef = useRef(Date.now().toString());
66
- // SSE (Server-Sent Events) source to receive live transcript messages
67
- var sourceRef = useRef(null);
68
- // Stores the first audio header (first 44 bytes of .wav file)
69
- var headerRef = useRef(null);
70
- // Stores the full accumulated transcript text
71
- var transcriptRef = useRef('');
72
- /**
73
- * Initializes audio capture and begins uploading chunks to the server
74
- */
75
- var startRecording = function () { return __awaiter(void 0, void 0, void 0, function () {
76
- var _a, _b, mediaRecorder, err_1;
77
- return __generator(this, function (_c) {
78
- switch (_c.label) {
79
- case 0:
80
- setRecordingStatus('connecting');
81
- _c.label = 1;
82
- case 1:
83
- _c.trys.push([1, 6, , 7]);
84
- if (!!hasRegisteredEncoder.current) return [3 /*break*/, 4];
85
- _a = register;
86
- return [4 /*yield*/, connect()];
87
- case 2: return [4 /*yield*/, _a.apply(void 0, [_c.sent()])];
88
- case 3:
89
- _c.sent();
90
- hasRegisteredEncoder.current = true;
91
- _c.label = 4;
92
- case 4:
93
- // Request microphone access
94
- _b = streamRef;
95
- return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ audio: true })];
96
- case 5:
97
- // Request microphone access
98
- _b.current = _c.sent();
99
- mediaRecorder = new MediaRecorder(streamRef.current, {
100
- mimeType: 'audio/wav',
101
- });
102
- // Triggered every time a chunk of audio is available
103
- mediaRecorder.ondataavailable = function (event) { return __awaiter(void 0, void 0, void 0, function () {
104
- var blob, formData, _a, content, err_2;
105
- return __generator(this, function (_b) {
106
- switch (_b.label) {
107
- case 0:
108
- if (!(event.data.size > 0)) return [3 /*break*/, 8];
109
- blob = event.data;
110
- formData = new FormData();
111
- if (!!headerRef.current) return [3 /*break*/, 2];
112
- _a = headerRef;
113
- return [4 /*yield*/, blob.arrayBuffer()];
114
- case 1:
115
- _a.current = (_b.sent()).slice(0, 44);
116
- return [3 /*break*/, 4];
117
- case 2: return [4 /*yield*/, blob.arrayBuffer()];
118
- case 3:
119
- content = _b.sent();
120
- blob = new Blob([headerRef.current, content], { type: blob.type });
121
- _b.label = 4;
122
- case 4:
123
- // Append audio chunk and session ID to the form data
124
- formData.append('audio', blob);
125
- formData.append('stream_id', streamIdRef.current);
126
- _b.label = 5;
127
- case 5:
128
- _b.trys.push([5, 7, , 8]);
129
- return [4 /*yield*/, fetch(audio_url, {
130
- method: 'POST',
131
- body: formData,
132
- })];
133
- case 6:
134
- _b.sent();
135
- return [3 /*break*/, 8];
136
- case 7:
137
- err_2 = _b.sent();
138
- console.error('Upload failed:', err_2);
139
- return [3 /*break*/, 8];
140
- case 8: return [2 /*return*/];
141
- }
142
- });
143
- }); };
144
- mediaRecorderRef.current = mediaRecorder;
145
- // Start recording with intervals
146
- mediaRecorder.start(interval);
147
- // Recording setup is complete
148
- setRecordingStatus('recording');
149
- return [3 /*break*/, 7];
150
- case 6:
151
- err_1 = _c.sent();
152
- console.error('Microphone access error:', err_1);
153
- setRecordingStatus('idle');
154
- return [3 /*break*/, 7];
155
- case 7: return [2 /*return*/];
156
- }
157
- });
158
- }); };
159
- /**
160
- * Starts listening for transcription updates via SSE
161
- */
162
- var startTranscriptStream = function () {
163
- // Open connection to transcript stream endpoint
164
- sourceRef.current = new EventSource("".concat(transcribe_url, "/").concat(streamIdRef.current));
165
- // Handle each incoming transcript message
166
- sourceRef.current.onmessage = function (event) {
167
- // Accumulate transcript and pass it to caller
168
- transcriptRef.current += event.data + '\n';
169
- onTranscript(transcriptRef.current);
170
- };
171
- // Handle SSE connection error
172
- sourceRef.current.onerror = function (err) {
173
- var _a;
174
- console.error('SSE error:', err);
175
- (_a = sourceRef.current) === null || _a === void 0 ? void 0 : _a.close();
176
- };
177
- };
178
- /**
179
- * Stops all active recording and streaming resources
180
- */
181
- var stopRecording = function () {
182
- var _a, _b, _c, _d;
183
- // Stop media recorder if it's active
184
- if (((_a = mediaRecorderRef.current) === null || _a === void 0 ? void 0 : _a.state) !== 'inactive') {
185
- (_b = mediaRecorderRef.current) === null || _b === void 0 ? void 0 : _b.stop();
186
- }
187
- // Stop and release mic stream
188
- (_c = streamRef.current) === null || _c === void 0 ? void 0 : _c.getTracks().forEach(function (track) { return track.stop(); });
189
- // Close SSE stream
190
- (_d = sourceRef.current) === null || _d === void 0 ? void 0 : _d.close();
191
- // Clear all refs
192
- mediaRecorderRef.current = null;
193
- streamRef.current = null;
194
- sourceRef.current = null;
195
- setRecordingStatus('idle');
196
- };
197
- /**
198
- * Public API to toggle between recording and stopped states
199
- */
200
- var toggleRecording = useCallback(function () {
201
- if (recordingStatus === 'recording' || recordingStatus === 'connecting') {
202
- stopRecording();
203
- }
204
- else {
205
- // Start a new session
206
- transcriptRef.current = '';
207
- streamIdRef.current = Date.now().toString(); // Unique session ID
208
- startRecording();
209
- startTranscriptStream();
210
- }
211
- }, [recordingStatus]);
212
- /**
213
- * Clean up everything when the component using this hook is unmounted
214
- */
215
- useEffect(function () {
216
- return function () { return stopRecording(); };
217
- }, []);
218
- return {
219
- recordingStatus: recordingStatus, // current status: 'idle' | 'connecting' | 'recording'
220
- toggleRecording: toggleRecording,
221
- };
222
- };
223
- export { useOpenAIRecorder };
@@ -1 +0,0 @@
1
- export { useOpenAIStream } from './useOpenAIStream';
@@ -1 +0,0 @@
1
- export { useOpenAIStream } from './useOpenAIStream';
@@ -1,14 +0,0 @@
1
- interface IOpenAIStreamOptions {
2
- temperature: number;
3
- top_p: number;
4
- }
5
- /**
6
- * Hook to stream OpenAI responses via a backend endpoint that acts as a proxy.
7
- *
8
- * @returns `stream`: a function that takes a prompt and streaming callback.
9
- */
10
- declare const useOpenAIStream: (url: string, authToken?: string) => {
11
- stream: (prompt: string, onText: (text: string) => Promise<void>, options?: IOpenAIStreamOptions) => Promise<void>;
12
- cancel: () => void;
13
- };
14
- export { useOpenAIStream, IOpenAIStreamOptions };