@longline/aqua-ui 1.0.330 → 1.0.334
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/Types.d.ts +9 -1
- package/containers/Anchor/Anchor.d.ts +2 -1
- package/containers/Anchor/Anchor.js +1 -1
- package/containers/Dock/Dock.d.ts +2 -1
- package/containers/Dock/Dock.js +1 -1
- package/containers/Dock/Dockable.d.ts +2 -1
- package/containers/Dock/Dockable.js +1 -1
- package/containers/DragBar/DragBar.d.ts +2 -1
- package/containers/DragBar/DragBar.js +1 -1
- package/containers/Form/elements/BoxWrapper.js +1 -1
- package/containers/Form/elements/Hint.js +1 -1
- package/containers/Form/elements/SimpleWrapper.js +1 -1
- package/containers/GlassPane/GlassPane.d.ts +2 -1
- package/containers/GlassPane/GlassPane.js +1 -1
- package/containers/InfoBox/InfoBox.d.ts +2 -1
- package/containers/InfoBox/InfoBox.js +1 -1
- package/containers/InfoBox/elements/Content.d.ts +2 -1
- package/containers/InfoBox/elements/Content.js +1 -1
- package/containers/InfoBox/elements/Footer.d.ts +2 -1
- package/containers/InfoBox/elements/Footer.js +1 -1
- package/containers/InfoBox/elements/Header.d.ts +2 -1
- package/containers/InfoBox/elements/Header.js +1 -1
- package/containers/InfoBox/elements/Row.d.ts +4 -2
- package/containers/InfoBox/elements/Row.js +1 -1
- package/containers/List/List.d.ts +2 -1
- package/containers/List/List.js +1 -1
- package/containers/List/ListCell.d.ts +2 -1
- package/containers/List/ListCell.js +1 -1
- package/containers/List/ListRow.d.ts +2 -1
- package/containers/List/ListRow.js +1 -1
- package/containers/Message/Message.d.ts +2 -1
- package/containers/Message/Message.js +1 -1
- package/containers/Openable/Openable.d.ts +2 -1
- package/containers/Openable/Openable.js +2 -2
- package/containers/PublicRoute/Help.d.ts +2 -1
- package/containers/PublicRoute/Help.js +1 -1
- package/containers/PublicRoute/PublicRoute.d.ts +2 -1
- package/containers/PublicRoute/PublicRoute.js +1 -1
- package/containers/Tabs/Pane.d.ts +2 -1
- package/containers/Tabs/Pane.js +1 -1
- package/containers/Tabs/Tabs.d.ts +2 -1
- package/containers/Tabs/Tabs.js +1 -1
- package/controls/Chip/Chip.d.ts +2 -1
- package/controls/Chip/Chip.js +1 -1
- package/controls/CircularProgress/CircularProgress.d.ts +2 -1
- package/controls/CircularProgress/CircularProgress.js +1 -1
- package/controls/Dropzone/Dropzone.d.ts +2 -1
- package/controls/Dropzone/Dropzone.js +1 -1
- package/controls/Fab/Fab.d.ts +2 -1
- package/controls/Fab/Fab.js +1 -1
- package/controls/Ghost/Ghost.d.ts +2 -1
- package/controls/Ghost/Ghost.js +1 -1
- package/controls/Gradient/Gradient.d.ts +2 -2
- package/controls/Gradient/Gradient.js +1 -1
- package/controls/Histogram/Histogram.d.ts +2 -1
- package/controls/Histogram/Histogram.js +14 -14
- package/controls/Icon/Icon.d.ts +2 -2
- package/controls/Icon/Icon.js +1 -1
- package/controls/Key/Key.d.ts +2 -1
- package/controls/Key/Key.js +1 -1
- package/controls/LinearChart/LinearChart.d.ts +2 -1
- package/controls/LinearChart/LinearChart.js +1 -1
- package/controls/ListButton/ListButton.d.ts +2 -1
- package/controls/ListButton/ListButton.js +1 -1
- package/controls/ListView/ListView.d.ts +2 -1
- package/controls/ListView/ListView.js +1 -1
- package/controls/Mouse/Mouse.d.ts +2 -1
- package/controls/Mouse/Mouse.js +1 -1
- package/controls/PrimaryButton/PrimaryButton.d.ts +2 -1
- package/controls/PrimaryButton/PrimaryButton.js +1 -1
- package/controls/Progress/Progress.d.ts +2 -1
- package/controls/Progress/Progress.js +1 -1
- package/controls/SecondaryButton/SecondaryButton.d.ts +2 -1
- package/controls/SecondaryButton/SecondaryButton.js +1 -1
- package/controls/TabBar/Tab.d.ts +2 -1
- package/controls/TabBar/Tab.js +1 -1
- package/controls/TabBar/TabBar.d.ts +2 -1
- package/controls/TabBar/TabBar.js +1 -1
- package/controls/TertiaryButton/TertiaryButton.d.ts +2 -1
- package/controls/TertiaryButton/TertiaryButton.js +1 -1
- package/controls/ToggleButton/ToggleButton.d.ts +2 -1
- package/controls/ToggleButton/ToggleButton.js +1 -1
- package/controls/View/View.d.ts +2 -1
- package/controls/View/View.js +1 -1
- package/hooks/useSpeechAIRecorder/index.d.ts +1 -0
- package/hooks/useSpeechAIRecorder/index.js +1 -0
- package/hooks/useSpeechAIRecorder/stories/SpeechAIAudioInput.d.ts +6 -0
- package/hooks/{useAssemblyAIRecorder/stories/AssemblyAudioInput.js → useSpeechAIRecorder/stories/SpeechAIAudioInput.js} +4 -4
- package/hooks/useSpeechAIRecorder/useSpeechAIRecorder.d.ts +29 -0
- package/hooks/{useAssemblyAIRecorder/useAssemblyAIRecorder.js → useSpeechAIRecorder/useSpeechAIRecorder.js} +13 -11
- package/hooks/useTextAIStream/index.d.ts +1 -0
- package/hooks/useTextAIStream/index.js +1 -0
- package/hooks/{useOpenAIStream/stories/OpenAIStreamInput.d.ts → useTextAIStream/stories/TextAIStreamInput.d.ts} +3 -3
- package/hooks/{useOpenAIStream/stories/OpenAIStreamInput.js → useTextAIStream/stories/TextAIStreamInput.js} +6 -6
- package/hooks/useTextAIStream/useTextAIStream.d.ts +26 -0
- package/hooks/{useOpenAIStream/useOpenAIStream.js → useTextAIStream/useTextAIStream.js} +16 -4
- package/inputs/DateInput/DateInput.d.ts +2 -5
- package/inputs/Dropdown/Dropdown.d.ts +2 -5
- package/inputs/Editor/Editor.d.ts +10 -11
- package/inputs/Editor/Editor.js +1 -1
- package/inputs/Editor/buttons/{SpeechButton.d.ts → SpeechAIButton.d.ts} +2 -2
- package/inputs/Editor/buttons/{SpeechButton.js → SpeechAIButton.js} +5 -5
- package/inputs/Editor/buttons/TextAIButton.d.ts +28 -0
- package/inputs/Editor/buttons/{OpenAIButton.js → TextAIButton.js} +13 -14
- package/inputs/Editor/buttons/{OpenAIMenu.d.ts → TextAIMenu.d.ts} +2 -2
- package/inputs/Editor/buttons/{OpenAIMenu.js → TextAIMenu.js} +3 -3
- package/inputs/Editor/menu/MenuBar.d.ts +6 -6
- package/inputs/Editor/menu/MenuBar.js +7 -7
- package/inputs/Input/Input.d.ts +2 -5
- package/inputs/Input/InputWrapper.d.ts +2 -1
- package/inputs/Input/InputWrapper.js +1 -1
- package/inputs/MonthRange/MonthRange.d.ts +2 -5
- package/inputs/Selector/Selector.d.ts +2 -5
- package/inputs/Slider/Slider.d.ts +2 -5
- package/inputs/Textarea/Textarea.d.ts +2 -5
- package/map/Map/Map.d.ts +2 -1
- package/map/Map/Map.js +1 -1
- package/map/PositionsManager/PositionBox.d.ts +2 -1
- package/map/PositionsManager/PositionBox.js +1 -1
- package/map/controls/CompassButton/CompassButton.js +3 -3
- package/map/controls/FullscreenButton/FullscreenButton.js +1 -1
- package/map/controls/Geocoder/Geocoder.js +1 -1
- package/map/controls/MapLoader/MapLoader.js +1 -1
- package/map/controls/ScaleControl/ScaleControl.js +1 -1
- package/map/controls/ZoomInButton/ZoomInButton.js +1 -1
- package/map/controls/ZoomOutButton/ZoomOutButton.js +1 -1
- package/map/controls/base/MapButton/MapButton.d.ts +0 -4
- package/map/controls/base/MapButton/MapButton.js +2 -2
- package/map/controls/base/MapControl/MapControl.d.ts +2 -1
- package/map/controls/base/MapControl/MapControl.js +2 -2
- package/modules/Filter/Filter.d.ts +2 -1
- package/modules/Filter/Filter.js +1 -1
- package/modules/MainMenu/Item.d.ts +2 -1
- package/modules/MainMenu/Item.js +1 -1
- package/modules/MainMenu/MainMenu.d.ts +2 -1
- package/modules/MainMenu/MainMenu.js +1 -1
- package/modules/Root/Sidebar.js +1 -1
- package/package.json +4 -5
- package/services/Dialog/Dialog.d.ts +2 -1
- package/services/Dialog/Dialog.js +2 -2
- package/services/Dialog/DialogWindow.d.ts +2 -1
- package/services/Dialog/DialogWindow.js +1 -1
- package/hooks/useAssemblyAIRecorder/index.d.ts +0 -1
- package/hooks/useAssemblyAIRecorder/index.js +0 -1
- package/hooks/useAssemblyAIRecorder/stories/AssemblyAudioInput.d.ts +0 -6
- package/hooks/useAssemblyAIRecorder/useAssemblyAIRecorder.d.ts +0 -27
- package/hooks/useOpenAIRecorder/index.d.ts +0 -1
- package/hooks/useOpenAIRecorder/index.js +0 -1
- package/hooks/useOpenAIRecorder/old/AudioInputNoHook.d.ts +0 -8
- package/hooks/useOpenAIRecorder/old/AudioInputNoHook.js +0 -192
- package/hooks/useOpenAIRecorder/old/AudioInputStandardMedia.d.ts +0 -5
- package/hooks/useOpenAIRecorder/old/AudioInputStandardMedia.js +0 -170
- package/hooks/useOpenAIRecorder/stories/OpenAIAudioInput.d.ts +0 -8
- package/hooks/useOpenAIRecorder/stories/OpenAIAudioInput.js +0 -17
- package/hooks/useOpenAIRecorder/useOpenAIRecorder.d.ts +0 -22
- package/hooks/useOpenAIRecorder/useOpenAIRecorder.js +0 -223
- package/hooks/useOpenAIStream/index.d.ts +0 -1
- package/hooks/useOpenAIStream/index.js +0 -1
- package/hooks/useOpenAIStream/useOpenAIStream.d.ts +0 -14
- package/inputs/Editor/buttons/OpenAIButton.d.ts +0 -29
- /package/hooks/{useAssemblyAIRecorder → useSpeechAIRecorder}/SpeechManager.d.ts +0 -0
- /package/hooks/{useAssemblyAIRecorder → useSpeechAIRecorder}/SpeechManager.js +0 -0
|
@@ -48,7 +48,7 @@ var MainMenuBase = function (props) {
|
|
|
48
48
|
primaryItems.push(child);
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
|
-
return (React.createElement("div", { "data-testid": "MainMenu", className: props.className },
|
|
51
|
+
return (React.createElement("div", { "data-testid": props['data-testid'] || "MainMenu", className: props.className },
|
|
52
52
|
React.createElement(Top, { "data-testid": "MainMenu.Top" }, primaryItems),
|
|
53
53
|
React.createElement(Bottom, { "data-testid": "MainMenu.Bottom" }, secondaryItems)));
|
|
54
54
|
};
|
package/modules/Root/Sidebar.js
CHANGED
|
@@ -16,7 +16,7 @@ var __assign = (this && this.__assign) || function () {
|
|
|
16
16
|
import * as React from 'react';
|
|
17
17
|
import styled from 'styled-components';
|
|
18
18
|
var SidebarBase = function (props) {
|
|
19
|
-
return
|
|
19
|
+
return React.createElement("div", { "data-testid": "Root.Sidebar", className: props.className }, props.children);
|
|
20
20
|
};
|
|
21
21
|
var SidebarStyled = styled(SidebarBase)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n // Position and size:\n position: absolute;\n z-index: 2;\n left: ", ";\n top: 0;\n width: 250px;\n bottom: 0;\n transition: left ", "ms ease-in-out;\n pointer-events: all;\n\n // Appearance:\n background: ", ";\n"], ["\n // Position and size:\n position: absolute;\n z-index: 2;\n left: ", ";\n top: 0;\n width: 250px;\n bottom: 0;\n transition: left ", "ms ease-in-out;\n pointer-events: all;\n\n // Appearance:\n background: ", ";\n"])), function (p) { return p.open ? 0 : '-350px'; }, function (p) { return p.theme.animation.duration * 2; }, function (p) { return p.theme.colors.primary[3]; });
|
|
22
22
|
var Sidebar = function (props) { return React.createElement(SidebarStyled, __assign({}, props)); };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longline/aqua-ui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.334",
|
|
4
4
|
"description": "AquaUI",
|
|
5
5
|
"author": "Alexander van Oostenrijk / Longline Environment",
|
|
6
6
|
"license": "Commercial",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "webpack --config webpack.config.js && tsc --version && tsc",
|
|
20
|
-
"storybook": "cross-env
|
|
21
|
-
"build-storybook": "cross-env
|
|
22
|
-
"build-storybook-gitlab": "cross-env
|
|
20
|
+
"storybook": "cross-env TEXTAI_RESPONSE_URL=http://api.flow/api/ai/anthropic/stream SPEECHAI_TOKEN_URL=http://api.flow/api/ai/assemblyai/get-token storybook dev -p 6006",
|
|
21
|
+
"build-storybook": "cross-env TEXTAI_RESPONSE_URL=http://api.flow/api/ai/anthropic/stream SPEECHAI_TOKEN_URL=http://api.flow/api/ai/assemblyai/get-token storybook build",
|
|
22
|
+
"build-storybook-gitlab": "cross-env TEXTAI_RESPONSE_URL=https://aquarisk.dev.longline.uk/api/ai/anthropic/stream SPEECHAI_TOKEN_URL=https://aquarisk.dev.longline.uk/api/ai/assemblyai/get-token storybook build",
|
|
23
23
|
"tsc": "tsc",
|
|
24
24
|
"pub": "npm version patch && webpack --config webpack.config.js && tsc && cd dist && npm publish"
|
|
25
25
|
},
|
|
@@ -58,7 +58,6 @@
|
|
|
58
58
|
"gl-matrix": "^3.4.3",
|
|
59
59
|
"mapbox-gl": "^3.9.4",
|
|
60
60
|
"marked": "^15.0.12",
|
|
61
|
-
"openai": "^5.0.1",
|
|
62
61
|
"overlayscrollbars-react": "^0.5.6",
|
|
63
62
|
"react": "^18.3.1",
|
|
64
63
|
"react-dom": "^18.3.1",
|
|
@@ -117,8 +117,8 @@ var DialogBase = function (props) {
|
|
|
117
117
|
toggle(props.open);
|
|
118
118
|
}, [props.open]);
|
|
119
119
|
return (React.createElement(React.Fragment, null, isMounted && React.createElement(React.Fragment, null,
|
|
120
|
-
createPortal(React.createElement(DialogBackground, { status: status }), document.body),
|
|
121
|
-
createPortal(React.createElement(DialogWindow, { inverted: props.inverted, width: props.width, ref: windowRef, status: status }, props.children), document.body))));
|
|
120
|
+
createPortal(React.createElement(DialogBackground, { "data-testid": "Dialog.Background", status: status }), document.body),
|
|
121
|
+
createPortal(React.createElement(DialogWindow, { "data-testid": props['data-testid'] || "Dialog.Window", inverted: props.inverted, width: props.width, ref: windowRef, status: status }, props.children), document.body))));
|
|
122
122
|
};
|
|
123
123
|
var Dialog = function (_a) {
|
|
124
124
|
var _b = _a.open, open = _b === void 0 ? false : _b, _c = _a.canClose, canClose = _c === void 0 ? true : _c, _d = _a.width, width = _d === void 0 ? 600 : _d, _e = _a.inverted, inverted = _e === void 0 ? false : _e, props = __rest(_a, ["open", "canClose", "width", "inverted"]);
|
|
@@ -9,7 +9,7 @@ var DialogWindowBase = React.forwardRef(function (props, ref) {
|
|
|
9
9
|
// Stop any keyboard interaction propagating to parent components.
|
|
10
10
|
ev.stopPropagation();
|
|
11
11
|
};
|
|
12
|
-
return (React.createElement("div", { "data-testid": "DialogWindow", className: "".concat(props.className, " ").concat(props.status), ref: ref, onKeyDown: handleKeyDown }, props.children));
|
|
12
|
+
return (React.createElement("div", { "data-testid": props['data-testid'] || "DialogWindow", className: "".concat(props.className, " ").concat(props.status), ref: ref, onKeyDown: handleKeyDown }, props.children));
|
|
13
13
|
});
|
|
14
14
|
var DialogWindow = styled(DialogWindowBase)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n position: fixed;\n z-index: 3000;\n left: 50%;\n top: 50%;\n transform-origin: center center;\n border-radius: ", "px;\n background-color: ", ";\n box-shadow: 0px 0px 10px 1px rgba(0,0,0,0.5);\n\n ", "\n\n // Font:\n font: ", ";\n color: ", "; \n\n /* Dialog window width:\n * Narrower on small screen. */\n width: ", ";\n @media (max-width: ", "px) {\n width: ", ";\n }\n\n /* useTransitionState classes */\n transition: opacity 0.5s ease, transform 0.5s cubic-bezier(.17,.89,.35,1.67);\n opacity: 0;\n &.preEnter, &.exiting {\n opacity: 0;\n transform: translateX(-50%) translateY(-50%) scale(0.8);\n }\n &.entering {\n opacity: 1;\n transform: translateX(-50%) translateY(-50%);\n }\n &.entered {\n opacity: 1;\n transform: translateX(-50%) translateY(-50%);\n }\n\n"], ["\n position: fixed;\n z-index: 3000;\n left: 50%;\n top: 50%;\n transform-origin: center center;\n border-radius: ", "px;\n background-color: ", ";\n box-shadow: 0px 0px 10px 1px rgba(0,0,0,0.5);\n\n ", "\n\n // Font:\n font: ", ";\n color: ", "; \n\n /* Dialog window width:\n * Narrower on small screen. */\n width: ", ";\n @media (max-width: ", "px) {\n width: ", ";\n }\n\n /* useTransitionState classes */\n transition: opacity 0.5s ease, transform 0.5s cubic-bezier(.17,.89,.35,1.67);\n opacity: 0;\n &.preEnter, &.exiting {\n opacity: 0;\n transform: translateX(-50%) translateY(-50%) scale(0.8);\n }\n &.entering {\n opacity: 1;\n transform: translateX(-50%) translateY(-50%);\n }\n &.entered {\n opacity: 1;\n transform: translateX(-50%) translateY(-50%);\n }\n\n"])), function (p) { return p.theme.radius.normal; }, function (p) { return p.inverted ? p.theme.colors.primary[3] : p.theme.colors.neutral[100]; }, function (p) { return p.inverted && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n .footer {\n background: ", ";\n } \n "], ["\n .footer {\n background: ", ";\n } \n "])), function (p) { return p.theme.colors.primary[5]; }); }, function (p) { return p.theme.font.bodyMedium; }, function (p) { return p.inverted ? p.theme.colors.neutral[100] : p.theme.colors.neutral[10]; }, function (p) {
|
|
15
15
|
if (!p.width)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { useAssemblyAIRecorder } from './useAssemblyAIRecorder';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { useAssemblyAIRecorder } from './useAssemblyAIRecorder';
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
type TranscriptCallback = (text: string) => void;
|
|
2
|
-
type TRecordingStatus = 'idle' | 'connecting' | 'recording';
|
|
3
|
-
/**
|
|
4
|
-
* useAssemblyAIRecorder
|
|
5
|
-
*
|
|
6
|
-
* A custom React hook for real-time audio transcription using AssemblyAI's
|
|
7
|
-
* streaming API.
|
|
8
|
-
*
|
|
9
|
-
* When recording is toggled on, it takes a few moments to establish a web
|
|
10
|
-
* socket connection. During this time, the recording status will be
|
|
11
|
-
* `'connecting'`.
|
|
12
|
-
*
|
|
13
|
-
* @param url - Back-end URL for obtaining temporary token
|
|
14
|
-
* @param onTranscript - Callback that receives updated transcript text.
|
|
15
|
-
* @returns An object containing:
|
|
16
|
-
* - recordingStatus: 'idle' | 'connecting' | 'recording'
|
|
17
|
-
* - toggleRecording: function to start or stop recording
|
|
18
|
-
*
|
|
19
|
-
* The `SpeechManager` singleton is use to keep track of which
|
|
20
|
-
* AssemblyAIRecorder is currently recording; when a new recording is started,
|
|
21
|
-
* the current one is stopped.
|
|
22
|
-
*/
|
|
23
|
-
declare const useAssemblyAIRecorder: (url: string, onTranscript: TranscriptCallback, authToken?: string) => {
|
|
24
|
-
recordingStatus: TRecordingStatus;
|
|
25
|
-
toggleRecording: () => Promise<void>;
|
|
26
|
-
};
|
|
27
|
-
export { useAssemblyAIRecorder, TRecordingStatus };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { useOpenAIRecorder } from './useOpenAIRecorder';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { useOpenAIRecorder } from './useOpenAIRecorder';
|
|
@@ -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,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,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 };
|