@corti/dictation-web 0.1.7 → 0.1.8
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/README.md +12 -12
- package/dist/CortiDictation.d.ts +6 -1
- package/dist/CortiDictation.js +35 -34
- package/dist/CortiDictation.js.map +1 -1
- package/dist/DictationService.d.ts +4 -4
- package/dist/DictationService.js +4 -11
- package/dist/DictationService.js.map +1 -1
- package/dist/RecorderManager.d.ts +2 -2
- package/dist/RecorderManager.js.map +1 -1
- package/dist/bundle.js +54 -81
- package/dist/components/settings-menu.js +3 -4
- package/dist/components/settings-menu.js.map +1 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/styles/callout.js +29 -29
- package/dist/styles/callout.js.map +1 -1
- package/dist/styles/theme.js +20 -41
- package/dist/styles/theme.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +2 -2
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,12 @@ Include the SDK in your project by importing the JavaScript module:
|
|
|
13
13
|
```html
|
|
14
14
|
npm i @corti/dictation-web
|
|
15
15
|
```
|
|
16
|
+
Then import the module like so:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
// Import the Corti Dictation SDK
|
|
20
|
+
import "@corti/dictation-web";
|
|
21
|
+
```
|
|
16
22
|
|
|
17
23
|
Alternatively, use a CDN to start quickly (not recommended).
|
|
18
24
|
|
|
@@ -36,11 +42,6 @@ Alternatively, use a CDN to start quickly (not recommended).
|
|
|
36
42
|
<!DOCTYPE html>
|
|
37
43
|
<html lang="en">
|
|
38
44
|
<body>
|
|
39
|
-
<script
|
|
40
|
-
src="https://cdn.jsdelivr.net/npm/@corti/dictation-web/dist/bundle.min.js"
|
|
41
|
-
preload
|
|
42
|
-
type="module"
|
|
43
|
-
></script>
|
|
44
45
|
<corti-dictation></corti-dictation>
|
|
45
46
|
<textarea
|
|
46
47
|
id="transcript"
|
|
@@ -48,8 +49,9 @@ Alternatively, use a CDN to start quickly (not recommended).
|
|
|
48
49
|
></textarea>
|
|
49
50
|
|
|
50
51
|
<script>
|
|
52
|
+
import "@corti/dictation-web";
|
|
51
53
|
const dictation = document.getElementById('transcript');
|
|
52
|
-
dictation.
|
|
54
|
+
dictation.setAccessToken("YOUR_AUTH_TOKEN") // Note: Never hardcode tokens
|
|
53
55
|
// Listen for events
|
|
54
56
|
dictationEl.addEventListener('transcript', e => {
|
|
55
57
|
document.getElementById('transcript').value += e.detail.data.text + ' ';
|
|
@@ -69,7 +71,6 @@ Alternatively, use a CDN to start quickly (not recommended).
|
|
|
69
71
|
| `selectedDevice` | Object | The selected device used for recording (MediaDeviceInfo). |
|
|
70
72
|
| `recordingState` | String | Current state of recording (`stopped`, `recording`, `initializing` and `stopping`, ). |
|
|
71
73
|
| `dictationConfig` | Object | Configuration settings for dictation. |
|
|
72
|
-
| `authToken` | String | Authentication token from OAuth server |
|
|
73
74
|
| `debug_displayAudio` | Boolean | Overrides any device selection and instead uses getDisplayMedia to stream system audio. SHould only be used for debugging |
|
|
74
75
|
|
|
75
76
|
### Methods
|
|
@@ -77,6 +78,7 @@ Alternatively, use a CDN to start quickly (not recommended).
|
|
|
77
78
|
| Method | Description |
|
|
78
79
|
| ------------------- | -------------------------- |
|
|
79
80
|
| `toggleRecording()` | Starts or stops recording. |
|
|
81
|
+
| `setAccessToken(access_token: string)` | Set the latest access token. This will return the server config. |
|
|
80
82
|
|
|
81
83
|
### Events
|
|
82
84
|
|
|
@@ -92,12 +94,10 @@ Alternatively, use a CDN to start quickly (not recommended).
|
|
|
92
94
|
|
|
93
95
|
## Authentication
|
|
94
96
|
|
|
95
|
-
This SDK does not handle OAuth 2.0 authentication. The client must provide an API key or access token as a string
|
|
96
|
-
|
|
97
|
-
## Notes
|
|
97
|
+
This SDK does not handle OAuth 2.0 authentication. The client must provide an API key or access token as a string using `setAccessToken`.
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
## Styling UI
|
|
100
|
+
If you use the. The UI supports dark and light mode based on browser preference. Alternatively, you can override the CSS variables used in the web component. Refer to our [Styling Guide](docs/styling.md).
|
|
101
101
|
|
|
102
102
|
## License
|
|
103
103
|
|
package/dist/CortiDictation.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ import type { DictationConfig, RecordingState } from './types.js';
|
|
|
6
6
|
export declare class CortiDictation extends LitElement {
|
|
7
7
|
static styles: import("lit").CSSResult[];
|
|
8
8
|
dictationConfig: DictationConfig;
|
|
9
|
-
authToken: string | undefined;
|
|
10
9
|
debug_displayAudio: boolean;
|
|
10
|
+
private _serverConfig;
|
|
11
11
|
private _audioLevel;
|
|
12
12
|
private _recordingState;
|
|
13
13
|
private _selectedDevice;
|
|
@@ -15,6 +15,11 @@ export declare class CortiDictation extends LitElement {
|
|
|
15
15
|
private recorderManager;
|
|
16
16
|
connectedCallback(): Promise<void>;
|
|
17
17
|
toggleRecording(): void;
|
|
18
|
+
setAccessToken(token: string): {
|
|
19
|
+
environment: string;
|
|
20
|
+
tenant: string;
|
|
21
|
+
accessToken: string;
|
|
22
|
+
};
|
|
18
23
|
get selectedDevice(): MediaDeviceInfo | null;
|
|
19
24
|
get recordingState(): RecordingState;
|
|
20
25
|
get devices(): MediaDeviceInfo[];
|
package/dist/CortiDictation.js
CHANGED
|
@@ -16,6 +16,7 @@ import ButtonStyles from './styles/buttons.js';
|
|
|
16
16
|
import ComponentStyles from './styles/ComponentStyles.js';
|
|
17
17
|
import { DEFAULT_DICTATION_CONFIG } from './constants.js';
|
|
18
18
|
import CalloutStyles from './styles/callout.js';
|
|
19
|
+
import { decodeToken } from './utils.js';
|
|
19
20
|
export class CortiDictation extends LitElement {
|
|
20
21
|
constructor() {
|
|
21
22
|
super(...arguments);
|
|
@@ -76,6 +77,14 @@ export class CortiDictation extends LitElement {
|
|
|
76
77
|
toggleRecording() {
|
|
77
78
|
this._toggleRecording();
|
|
78
79
|
}
|
|
80
|
+
setAccessToken(token) {
|
|
81
|
+
const decoded = decodeToken(token);
|
|
82
|
+
if (!decoded) {
|
|
83
|
+
throw new Error('Invalid token');
|
|
84
|
+
}
|
|
85
|
+
this._serverConfig = decoded;
|
|
86
|
+
return decoded;
|
|
87
|
+
}
|
|
79
88
|
get selectedDevice() {
|
|
80
89
|
return this.recorderManager.selectedDevice || null;
|
|
81
90
|
}
|
|
@@ -88,18 +97,18 @@ export class CortiDictation extends LitElement {
|
|
|
88
97
|
async setRecordingDevice(device) {
|
|
89
98
|
this.recorderManager.selectedDevice = device;
|
|
90
99
|
this._selectedDevice = device;
|
|
91
|
-
if (!this.
|
|
100
|
+
if (!this._serverConfig)
|
|
92
101
|
return;
|
|
93
102
|
if (this._recordingState === 'recording') {
|
|
94
103
|
await this.recorderManager.stopRecording();
|
|
95
104
|
await this.recorderManager.startRecording({
|
|
96
105
|
dictationConfig: this.dictationConfig,
|
|
97
|
-
|
|
106
|
+
serverConfig: this._serverConfig,
|
|
98
107
|
});
|
|
99
108
|
}
|
|
100
109
|
}
|
|
101
110
|
_toggleRecording() {
|
|
102
|
-
if (!this.
|
|
111
|
+
if (!this._serverConfig)
|
|
103
112
|
return;
|
|
104
113
|
if (this._recordingState === 'recording') {
|
|
105
114
|
this.recorderManager.stopRecording();
|
|
@@ -107,7 +116,7 @@ export class CortiDictation extends LitElement {
|
|
|
107
116
|
else if (this._recordingState === 'stopped') {
|
|
108
117
|
this.recorderManager.startRecording({
|
|
109
118
|
dictationConfig: this.dictationConfig,
|
|
110
|
-
|
|
119
|
+
serverConfig: this._serverConfig,
|
|
111
120
|
debug_displayAudio: this.debug_displayAudio,
|
|
112
121
|
});
|
|
113
122
|
}
|
|
@@ -118,40 +127,32 @@ export class CortiDictation extends LitElement {
|
|
|
118
127
|
this.setRecordingDevice(customEvent.detail.selectedDevice);
|
|
119
128
|
}
|
|
120
129
|
render() {
|
|
121
|
-
const isConfigured = this.authToken;
|
|
122
|
-
if (!isConfigured) {
|
|
123
|
-
return html `
|
|
124
|
-
<div class="wrapper">
|
|
125
|
-
<div class="callout red small">No Auth Token</div>
|
|
126
|
-
</div>
|
|
127
|
-
`;
|
|
128
|
-
}
|
|
129
130
|
const isLoading = this._recordingState === 'initializing' ||
|
|
130
131
|
this._recordingState === 'stopping';
|
|
131
132
|
const isRecording = this._recordingState === 'recording';
|
|
132
|
-
return html `
|
|
133
|
-
<div class="wrapper">
|
|
134
|
-
<button
|
|
135
|
-
@click=${this._toggleRecording}
|
|
136
|
-
class=${isRecording ? 'red' : 'accent'}
|
|
137
|
-
>
|
|
133
|
+
return html `
|
|
134
|
+
<div class="wrapper">
|
|
135
|
+
<button
|
|
136
|
+
@click=${this._toggleRecording}
|
|
137
|
+
class=${isRecording ? 'red' : 'accent'}
|
|
138
|
+
>
|
|
138
139
|
${isLoading
|
|
139
140
|
? html `<icon-loading-spinner></icon-loading-spinner>`
|
|
140
141
|
: isRecording
|
|
141
142
|
? html `<icon-recording></icon-recording>`
|
|
142
|
-
: html `<icon-mic-on></icon-mic-on>`}
|
|
143
|
-
<audio-visualiser
|
|
144
|
-
.level=${this._audioLevel}
|
|
145
|
-
.active=${isRecording}
|
|
146
|
-
></audio-visualiser>
|
|
147
|
-
</button>
|
|
148
|
-
|
|
149
|
-
<settings-menu
|
|
150
|
-
.selectedDevice=${this._selectedDevice}
|
|
151
|
-
?settingsDisabled=${this._recordingState !== 'stopped'}
|
|
152
|
-
@recording-devices-changed=${this._onRecordingDevicesChanged}
|
|
153
|
-
></settings-menu>
|
|
154
|
-
</div>
|
|
143
|
+
: html `<icon-mic-on></icon-mic-on>`}
|
|
144
|
+
<audio-visualiser
|
|
145
|
+
.level=${this._audioLevel}
|
|
146
|
+
.active=${isRecording}
|
|
147
|
+
></audio-visualiser>
|
|
148
|
+
</button>
|
|
149
|
+
|
|
150
|
+
<settings-menu
|
|
151
|
+
.selectedDevice=${this._selectedDevice}
|
|
152
|
+
?settingsDisabled=${this._recordingState !== 'stopped'}
|
|
153
|
+
@recording-devices-changed=${this._onRecordingDevicesChanged}
|
|
154
|
+
></settings-menu>
|
|
155
|
+
</div>
|
|
155
156
|
`;
|
|
156
157
|
}
|
|
157
158
|
}
|
|
@@ -159,12 +160,12 @@ CortiDictation.styles = [ButtonStyles, ThemeStyles, ComponentStyles, CalloutStyl
|
|
|
159
160
|
__decorate([
|
|
160
161
|
property({ type: Object })
|
|
161
162
|
], CortiDictation.prototype, "dictationConfig", void 0);
|
|
162
|
-
__decorate([
|
|
163
|
-
property({ type: String })
|
|
164
|
-
], CortiDictation.prototype, "authToken", void 0);
|
|
165
163
|
__decorate([
|
|
166
164
|
property({ type: Boolean })
|
|
167
165
|
], CortiDictation.prototype, "debug_displayAudio", void 0);
|
|
166
|
+
__decorate([
|
|
167
|
+
state()
|
|
168
|
+
], CortiDictation.prototype, "_serverConfig", void 0);
|
|
168
169
|
__decorate([
|
|
169
170
|
state()
|
|
170
171
|
], CortiDictation.prototype, "_audioLevel", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CortiDictation.js","sourceRoot":"","sources":["../src/CortiDictation.ts"],"names":[],"mappings":"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","sourcesContent":["// corti-dictation.ts\r\nimport { html, LitElement } from 'lit';\r\nimport { property, state } from 'lit/decorators.js';\r\nimport { RecorderManager } from './RecorderManager.js';\r\nimport './components/settings-menu.js';\r\nimport './components/audio-visualiser.js';\r\nimport './icons/icons.js';\r\nimport ThemeStyles from './styles/theme.js';\r\nimport ButtonStyles from './styles/buttons.js';\r\nimport ComponentStyles from './styles/ComponentStyles.js';\r\n\r\nimport type { DictationConfig, RecordingState } from './types.js';\r\nimport { DEFAULT_DICTATION_CONFIG } from './constants.js';\r\nimport CalloutStyles from './styles/callout.js';\r\n\r\nexport class CortiDictation extends LitElement {\r\n static styles = [ButtonStyles, ThemeStyles, ComponentStyles, CalloutStyles];\r\n\r\n @property({ type: Object })\r\n dictationConfig: DictationConfig = DEFAULT_DICTATION_CONFIG;\r\n\r\n @property({ type: String })\r\n authToken: string | undefined;\r\n\r\n @property({ type: Boolean })\r\n debug_displayAudio: boolean = false;\r\n\r\n @state()\r\n private _audioLevel: number = 0;\r\n\r\n @state()\r\n private _recordingState: RecordingState = 'stopped';\r\n\r\n @state()\r\n private _selectedDevice: MediaDeviceInfo | undefined;\r\n\r\n @state()\r\n private _devices: MediaDeviceInfo[] = [];\r\n\r\n private recorderManager = new RecorderManager();\r\n\r\n async connectedCallback() {\r\n super.connectedCallback();\r\n const devices = await this.recorderManager.initialize();\r\n if (devices.selectedDevice) {\r\n this._selectedDevice = this.recorderManager.selectedDevice;\r\n this._devices = this.recorderManager.devices;\r\n this.dispatchEvent(new CustomEvent('ready'));\r\n }\r\n\r\n // Map event names to any extra handling logic\r\n const eventHandlers: Record<string, (e: CustomEvent) => void> = {\r\n 'recording-state-changed': e => {\r\n this._recordingState = e.detail.state;\r\n },\r\n 'devices-changed': () => {\r\n this._devices = [...this.recorderManager.devices];\r\n this.requestUpdate();\r\n },\r\n 'audio-level-changed': e => {\r\n this._audioLevel = e.detail.audioLevel;\r\n this.requestUpdate();\r\n },\r\n };\r\n\r\n const eventsToRelay = [\r\n 'recording-state-changed',\r\n 'recording-devices-changed',\r\n 'audio-level-changed',\r\n 'error',\r\n 'transcript',\r\n 'command',\r\n 'ready',\r\n ];\r\n\r\n eventsToRelay.forEach(eventName => {\r\n this.recorderManager.addEventListener(eventName, (e: Event) => {\r\n const customEvent = e as CustomEvent;\r\n // Perform any additional handling if defined\r\n if (eventHandlers[eventName]) {\r\n eventHandlers[eventName](customEvent);\r\n }\r\n // Re-dispatch the event from the component\r\n this.dispatchEvent(\r\n new CustomEvent(eventName, {\r\n detail: customEvent.detail,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n });\r\n });\r\n }\r\n\r\n public toggleRecording() {\r\n this._toggleRecording();\r\n }\r\n\r\n public get selectedDevice(): MediaDeviceInfo | null {\r\n return this.recorderManager.selectedDevice || null;\r\n }\r\n\r\n public get recordingState(): RecordingState {\r\n return this._recordingState;\r\n }\r\n\r\n public get devices(): MediaDeviceInfo[] {\r\n return this._devices;\r\n }\r\n\r\n public async setRecordingDevice(device: MediaDeviceInfo) {\r\n this.recorderManager.selectedDevice = device;\r\n this._selectedDevice = device;\r\n if (!this.authToken) return;\r\n if (this._recordingState === 'recording') {\r\n await this.recorderManager.stopRecording();\r\n await this.recorderManager.startRecording({\r\n dictationConfig: this.dictationConfig,\r\n authToken: this.authToken,\r\n });\r\n }\r\n }\r\n\r\n _toggleRecording() {\r\n if (!this.authToken) return;\r\n if (this._recordingState === 'recording') {\r\n this.recorderManager.stopRecording();\r\n } else if (this._recordingState === 'stopped') {\r\n this.recorderManager.startRecording({\r\n dictationConfig: this.dictationConfig,\r\n authToken: this.authToken,\r\n debug_displayAudio: this.debug_displayAudio,\r\n });\r\n }\r\n }\r\n\r\n // Handle device change events if needed\r\n async _onRecordingDevicesChanged(event: Event) {\r\n const customEvent = event as CustomEvent;\r\n this.setRecordingDevice(customEvent.detail.selectedDevice);\r\n }\r\n\r\n render() {\r\n const isConfigured = this.authToken;\r\n if (!isConfigured) {\r\n return html`\r\n <div class=\"wrapper\">\r\n <div class=\"callout red small\">No Auth Token</div>\r\n </div>\r\n `;\r\n }\r\n\r\n const isLoading =\r\n this._recordingState === 'initializing' ||\r\n this._recordingState === 'stopping';\r\n const isRecording = this._recordingState === 'recording';\r\n return html`\r\n <div class=\"wrapper\">\r\n <button\r\n @click=${this._toggleRecording}\r\n class=${isRecording ? 'red' : 'accent'}\r\n >\r\n ${isLoading\r\n ? html`<icon-loading-spinner></icon-loading-spinner>`\r\n : isRecording\r\n ? html`<icon-recording></icon-recording>`\r\n : html`<icon-mic-on></icon-mic-on>`}\r\n <audio-visualiser\r\n .level=${this._audioLevel}\r\n .active=${isRecording}\r\n ></audio-visualiser>\r\n </button>\r\n\r\n <settings-menu\r\n .selectedDevice=${this._selectedDevice}\r\n ?settingsDisabled=${this._recordingState !== 'stopped'}\r\n @recording-devices-changed=${this._onRecordingDevicesChanged}\r\n ></settings-menu>\r\n </div>\r\n `;\r\n }\r\n}\r\n\r\nexport default CortiDictation;\r\n"]}
|
|
1
|
+
{"version":3,"file":"CortiDictation.js","sourceRoot":"","sources":["../src/CortiDictation.ts"],"names":[],"mappings":"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","sourcesContent":["// corti-dictation.ts\nimport { html, LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { RecorderManager } from './RecorderManager.js';\nimport './components/settings-menu.js';\nimport './components/audio-visualiser.js';\nimport './icons/icons.js';\nimport ThemeStyles from './styles/theme.js';\nimport ButtonStyles from './styles/buttons.js';\nimport ComponentStyles from './styles/ComponentStyles.js';\n\nimport type { DictationConfig, RecordingState, ServerConfig } from './types.js';\nimport { DEFAULT_DICTATION_CONFIG } from './constants.js';\nimport CalloutStyles from './styles/callout.js';\nimport { decodeToken } from './utils.js';\n\nexport class CortiDictation extends LitElement {\n static styles = [ButtonStyles, ThemeStyles, ComponentStyles, CalloutStyles];\n\n @property({ type: Object })\n dictationConfig: DictationConfig = DEFAULT_DICTATION_CONFIG;\n\n @property({ type: Boolean })\n debug_displayAudio: boolean = false;\n\n @state()\n private _serverConfig: ServerConfig | undefined;\n\n @state()\n private _audioLevel: number = 0;\n\n @state()\n private _recordingState: RecordingState = 'stopped';\n\n @state()\n private _selectedDevice: MediaDeviceInfo | undefined;\n\n @state()\n private _devices: MediaDeviceInfo[] = [];\n\n private recorderManager = new RecorderManager();\n\n async connectedCallback() {\n super.connectedCallback();\n const devices = await this.recorderManager.initialize();\n if (devices.selectedDevice) {\n this._selectedDevice = this.recorderManager.selectedDevice;\n this._devices = this.recorderManager.devices;\n this.dispatchEvent(new CustomEvent('ready'));\n }\n\n // Map event names to any extra handling logic\n const eventHandlers: Record<string, (e: CustomEvent) => void> = {\n 'recording-state-changed': e => {\n this._recordingState = e.detail.state;\n },\n 'devices-changed': () => {\n this._devices = [...this.recorderManager.devices];\n this.requestUpdate();\n },\n 'audio-level-changed': e => {\n this._audioLevel = e.detail.audioLevel;\n this.requestUpdate();\n },\n };\n\n const eventsToRelay = [\n 'recording-state-changed',\n 'recording-devices-changed',\n 'audio-level-changed',\n 'error',\n 'transcript',\n 'command',\n 'ready',\n ];\n\n eventsToRelay.forEach(eventName => {\n this.recorderManager.addEventListener(eventName, (e: Event) => {\n const customEvent = e as CustomEvent;\n // Perform any additional handling if defined\n if (eventHandlers[eventName]) {\n eventHandlers[eventName](customEvent);\n }\n // Re-dispatch the event from the component\n this.dispatchEvent(\n new CustomEvent(eventName, {\n detail: customEvent.detail,\n bubbles: true,\n composed: true,\n }),\n );\n });\n });\n }\n\n public toggleRecording() {\n this._toggleRecording();\n }\n\n public setAccessToken(token: string) {\n const decoded = decodeToken(token);\n if (!decoded) {\n throw new Error('Invalid token');\n }\n this._serverConfig = decoded;\n return decoded;\n }\n\n public get selectedDevice(): MediaDeviceInfo | null {\n return this.recorderManager.selectedDevice || null;\n }\n\n public get recordingState(): RecordingState {\n return this._recordingState;\n }\n\n public get devices(): MediaDeviceInfo[] {\n return this._devices;\n }\n\n public async setRecordingDevice(device: MediaDeviceInfo) {\n this.recorderManager.selectedDevice = device;\n this._selectedDevice = device;\n if (!this._serverConfig) return;\n if (this._recordingState === 'recording') {\n await this.recorderManager.stopRecording();\n await this.recorderManager.startRecording({\n dictationConfig: this.dictationConfig,\n serverConfig: this._serverConfig,\n });\n }\n }\n\n _toggleRecording() {\n if (!this._serverConfig) return;\n if (this._recordingState === 'recording') {\n this.recorderManager.stopRecording();\n } else if (this._recordingState === 'stopped') {\n this.recorderManager.startRecording({\n dictationConfig: this.dictationConfig,\n serverConfig: this._serverConfig,\n debug_displayAudio: this.debug_displayAudio,\n });\n }\n }\n\n // Handle device change events if needed\n async _onRecordingDevicesChanged(event: Event) {\n const customEvent = event as CustomEvent;\n this.setRecordingDevice(customEvent.detail.selectedDevice);\n }\n\n render() {\n const isLoading =\n this._recordingState === 'initializing' ||\n this._recordingState === 'stopping';\n const isRecording = this._recordingState === 'recording';\n return html`\n <div class=\"wrapper\">\n <button\n @click=${this._toggleRecording}\n class=${isRecording ? 'red' : 'accent'}\n >\n ${isLoading\n ? html`<icon-loading-spinner></icon-loading-spinner>`\n : isRecording\n ? html`<icon-recording></icon-recording>`\n : html`<icon-mic-on></icon-mic-on>`}\n <audio-visualiser\n .level=${this._audioLevel}\n .active=${isRecording}\n ></audio-visualiser>\n </button>\n\n <settings-menu\n .selectedDevice=${this._selectedDevice}\n ?settingsDisabled=${this._recordingState !== 'stopped'}\n @recording-devices-changed=${this._onRecordingDevicesChanged}\n ></settings-menu>\n </div>\n `;\n }\n}\n\nexport default CortiDictation;\n"]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { DictationConfig } from './types.js';
|
|
1
|
+
import type { DictationConfig, ServerConfig } from './types.js';
|
|
2
2
|
export declare class DictationService extends EventTarget {
|
|
3
3
|
private mediaRecorder;
|
|
4
4
|
private webSocket;
|
|
5
|
-
private
|
|
5
|
+
private serverConfig;
|
|
6
6
|
private dictationConfig;
|
|
7
|
-
constructor(mediaStream: MediaStream, { dictationConfig,
|
|
7
|
+
constructor(mediaStream: MediaStream, { dictationConfig, serverConfig, }: {
|
|
8
8
|
dictationConfig: DictationConfig;
|
|
9
|
-
|
|
9
|
+
serverConfig: ServerConfig;
|
|
10
10
|
});
|
|
11
11
|
private dispatchCustomEvent;
|
|
12
12
|
startRecording(): void;
|
package/dist/DictationService.js
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import { decodeToken } from './utils.js';
|
|
2
1
|
export class DictationService extends EventTarget {
|
|
3
|
-
constructor(mediaStream, { dictationConfig,
|
|
2
|
+
constructor(mediaStream, { dictationConfig, serverConfig, }) {
|
|
4
3
|
super();
|
|
5
4
|
this.mediaRecorder = new MediaRecorder(mediaStream);
|
|
6
|
-
this.
|
|
5
|
+
this.serverConfig = serverConfig;
|
|
7
6
|
this.dictationConfig = dictationConfig;
|
|
8
|
-
// Decode token during construction.
|
|
9
|
-
const config = decodeToken(this.authToken);
|
|
10
|
-
if (!config) {
|
|
11
|
-
throw new Error('Invalid token');
|
|
12
|
-
}
|
|
13
7
|
this.mediaRecorder.ondataavailable = event => {
|
|
14
8
|
if (this.webSocket?.readyState === WebSocket.OPEN) {
|
|
15
9
|
this.webSocket.send(event.data);
|
|
@@ -24,8 +18,7 @@ export class DictationService extends EventTarget {
|
|
|
24
18
|
}));
|
|
25
19
|
}
|
|
26
20
|
startRecording() {
|
|
27
|
-
|
|
28
|
-
if (!serverConfig) {
|
|
21
|
+
if (!this.serverConfig) {
|
|
29
22
|
this.dispatchEvent(new CustomEvent('error', {
|
|
30
23
|
detail: 'Invalid token',
|
|
31
24
|
bubbles: true,
|
|
@@ -33,7 +26,7 @@ export class DictationService extends EventTarget {
|
|
|
33
26
|
}));
|
|
34
27
|
return;
|
|
35
28
|
}
|
|
36
|
-
const url = `wss://api.${serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${serverConfig.tenant}&token=Bearer%20${this.
|
|
29
|
+
const url = `wss://api.${this.serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${this.serverConfig.tenant}&token=Bearer%20${this.serverConfig.accessToken}`;
|
|
37
30
|
this.webSocket = new WebSocket(url);
|
|
38
31
|
this.webSocket.onopen = () => {
|
|
39
32
|
this.webSocket.send(JSON.stringify({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DictationService.js","sourceRoot":"","sources":["../src/DictationService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DictationService.js","sourceRoot":"","sources":["../src/DictationService.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DictationConfig, ServerConfig } from './types.js';\n\nexport class DictationService extends EventTarget {\n private mediaRecorder: MediaRecorder;\n private webSocket!: WebSocket;\n private serverConfig: ServerConfig;\n private dictationConfig: DictationConfig;\n\n constructor(\n mediaStream: MediaStream,\n {\n dictationConfig,\n serverConfig,\n }: { dictationConfig: DictationConfig; serverConfig: ServerConfig },\n ) {\n super();\n this.mediaRecorder = new MediaRecorder(mediaStream);\n this.serverConfig = serverConfig;\n this.dictationConfig = dictationConfig;\n\n this.mediaRecorder.ondataavailable = event => {\n if (this.webSocket?.readyState === WebSocket.OPEN) {\n this.webSocket.send(event.data);\n }\n };\n }\n\n private dispatchCustomEvent(eventName: string, detail?: unknown): void {\n this.dispatchEvent(\n new CustomEvent(eventName, {\n detail,\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n public startRecording() {\n if (!this.serverConfig) {\n this.dispatchEvent(\n new CustomEvent('error', {\n detail: 'Invalid token',\n bubbles: true,\n composed: true,\n }),\n );\n return;\n }\n\n const url = `wss://api.${this.serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${this.serverConfig.tenant}&token=Bearer%20${this.serverConfig.accessToken}`;\n this.webSocket = new WebSocket(url);\n\n this.webSocket.onopen = () => {\n this.webSocket.send(\n JSON.stringify({\n type: 'config',\n configuration: this.dictationConfig,\n }),\n );\n };\n\n this.webSocket.onmessage = event => {\n const message = JSON.parse(event.data);\n switch (message.type) {\n case 'CONFIG_ACCEPTED':\n this.mediaRecorder.start(250);\n break;\n case 'CONFIG_DENIED':\n this.dispatchCustomEvent('error', message);\n return this.stopRecording();\n case 'transcript':\n this.dispatchCustomEvent('transcript', message);\n break;\n case 'command':\n this.dispatchCustomEvent('command', message);\n break;\n default:\n console.warn(`Unhandled message type: ${message.type}`);\n break;\n }\n };\n\n this.webSocket.onerror = event => {\n this.dispatchCustomEvent('error', event);\n };\n\n this.webSocket.onclose = event => {\n this.dispatchCustomEvent('stream-closed', event);\n };\n }\n\n public async stopRecording(): Promise<void> {\n this.mediaRecorder?.stop();\n\n if (this.webSocket?.readyState === WebSocket.OPEN) {\n this.webSocket.send(JSON.stringify({ type: 'end' }));\n }\n\n const timeout: NodeJS.Timeout = setTimeout(() => {\n if (this.webSocket?.readyState === WebSocket.OPEN) {\n this.webSocket.close();\n }\n }, 10000);\n\n this.webSocket.onclose = () => {\n this.webSocket?.close();\n clearTimeout(timeout);\n };\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DictationConfig, RecordingState } from './types.js';
|
|
1
|
+
import type { DictationConfig, RecordingState, ServerConfig } from './types.js';
|
|
2
2
|
export declare class RecorderManager extends EventTarget {
|
|
3
3
|
devices: MediaDeviceInfo[];
|
|
4
4
|
selectedDevice: MediaDeviceInfo | undefined;
|
|
@@ -16,7 +16,7 @@ export declare class RecorderManager extends EventTarget {
|
|
|
16
16
|
private handleDevicesChange;
|
|
17
17
|
startRecording(params: {
|
|
18
18
|
dictationConfig: DictationConfig;
|
|
19
|
-
|
|
19
|
+
serverConfig: ServerConfig;
|
|
20
20
|
debug_displayAudio?: boolean;
|
|
21
21
|
}): Promise<void>;
|
|
22
22
|
stopRecording(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecorderManager.js","sourceRoot":"","sources":["../src/RecorderManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,MAAM,OAAO,eAAgB,SAAQ,WAAW;IAe9C;QACE,KAAK,EAAE,CAAC;QAfH,YAAO,GAAsB,EAAE,CAAC;QAIhC,mBAAc,GAAmB,SAAS,CAAC;QAE1C,iBAAY,GAAuB,IAAI,CAAC;QAExC,kBAAa,GAAwB,IAAI,CAAC;QAE1C,sBAAiB,GAA4B,IAAI,CAAC;QAMxD,SAAS,CAAC,YAAY,CAAC,gBAAgB,CACrC,cAAc,EACd,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CACpC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC;QACtC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC,aAAa,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;IACxE,CAAC;IAEO,mBAAmB,CAAC,SAAiB,EAAE,MAAgB;QAC7D,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,SAAS,EAAE;YACzB,MAAM;YACN,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC;QACtC,IACE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAChB,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,cAAc,EAAE,QAAQ,CAC5D,EACD,CAAC;YACD,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC,aAAa,CAAC;QACrD,CAAC;QACD,IAAI,CAAC,mBAAmB,CAAC,2BAA2B,EAAE;YACpD,OAAO,EAAE,cAAc,CAAC,OAAO;YAC/B,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,aAAa;SACpE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,MAIpB;QACC,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAE3C,IAAI,CAAC;YACH,IAAI,CAAC,YAAY,GAAG,MAAM,cAAc,CACtC,MAAM,CAAC,kBAAkB;gBACvB,CAAC,CAAC,eAAe;gBACjB,CAAC,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAClC,CAAC;YAEF,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAuB,EAAE,EAAE;gBAChE,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;oBACnC,IAAI,IAAI,CAAC,cAAc,KAAK,WAAW,EAAE,CAAC;wBACxC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE;4BAChC,OAAO,EAAE,6BAA6B;yBACvC,CAAC,CAAC;wBACH,IAAI,CAAC,aAAa,EAAE,CAAC;oBACvB,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,aAAa,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,gCAAgC;QAChC,IAAI,CAAC;YACH,IAAI,CAAC,iBAAiB,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YAEzE,+CAA+C;YAC/C,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE;gBACnD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,OAAO,EAAE;oBACvB,MAAM,EAAG,CAAiB,CAAC,MAAM;oBACjC,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,IAAI;iBACf,CAAC,CACH,CAAC;gBACF,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,eAAe,EAAE,GAAG,EAAE,CAC5D,IAAI,CAAC,aAAa,EAAE,CACrB,CAAC;YACF,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,CACxD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,YAAY,EAAE;gBAC5B,MAAM,EAAG,CAAiB,CAAC,MAAM;gBACjC,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;aACf,CAAC,CACH,CACF,CAAC;YACF,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CACrD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,SAAS,EAAE;gBACzB,MAAM,EAAG,CAAiB,CAAC,MAAM;gBACjC,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;aACf,CAAC,CACH,CACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,iBAAiB,EAAE,cAAc,EAAE,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,OAAO,EAAE;gBACvB,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;aACf,CAAC,CACH,CAAC;YACF,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAExC,oCAAoC;QACpC,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;YACjD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa;gBAC9B,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,EAAE,GAAG,CAAC;gBACxC,CAAC,CAAC,CAAC,CAAC;YACN,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QACzE,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,aAAa,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACxC,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;QACvC,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;QACnE,MAAM,IAAI,CAAC,iBAAiB,EAAE,aAAa,EAAE,CAAC;QAC9C,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IAEO,qBAAqB,CAAC,KAAqB;QACjD,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,yBAAyB,EAAE;YACzC,MAAM,EAAE,EAAE,KAAK,EAAE;YACjB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { getAudioDevices, getMediaStream } from './utils.js';\r\nimport { AudioService } from './audioService.js';\r\nimport { DictationService } from './DictationService.js';\r\nimport type { DictationConfig, RecordingState } from './types.js';\r\n\r\nexport class RecorderManager extends EventTarget {\r\n public devices: MediaDeviceInfo[] = [];\r\n\r\n public selectedDevice: MediaDeviceInfo | undefined;\r\n\r\n public recordingState: RecordingState = 'stopped';\r\n\r\n private _mediaStream: MediaStream | null = null;\r\n\r\n private _audioService: AudioService | null = null;\r\n\r\n private _dictationService: DictationService | null = null;\r\n\r\n private _visualiserInterval?: number;\r\n\r\n constructor() {\r\n super();\r\n navigator.mediaDevices.addEventListener(\r\n 'devicechange',\r\n this.handleDevicesChange.bind(this),\r\n );\r\n }\r\n\r\n async initialize() {\r\n const deviceResponse = await getAudioDevices();\r\n this.devices = deviceResponse.devices;\r\n this.selectedDevice = deviceResponse.defaultDevice;\r\n return { devices: this.devices, selectedDevice: this.selectedDevice };\r\n }\r\n\r\n private dispatchCustomEvent(eventName: string, detail?: unknown): void {\r\n this.dispatchEvent(\r\n new CustomEvent(eventName, {\r\n detail,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n\r\n private async handleDevicesChange() {\r\n const deviceResponse = await getAudioDevices();\r\n this.devices = deviceResponse.devices;\r\n if (\r\n !this.devices.find(\r\n device => device.deviceId === this.selectedDevice?.deviceId,\r\n )\r\n ) {\r\n this.selectedDevice = deviceResponse.defaultDevice;\r\n }\r\n this.dispatchCustomEvent('recording-devices-changed', {\r\n devices: deviceResponse.devices,\r\n selectedDevice: this.selectedDevice || deviceResponse.defaultDevice,\r\n });\r\n }\r\n\r\n async startRecording(params: {\r\n dictationConfig: DictationConfig;\r\n authToken: string;\r\n debug_displayAudio?: boolean;\r\n }): Promise<void> {\r\n this._updateRecordingState('initializing');\r\n\r\n try {\r\n this._mediaStream = await getMediaStream(\r\n params.debug_displayAudio\r\n ? 'display_audio'\r\n : this.selectedDevice?.deviceId,\r\n );\r\n\r\n this._mediaStream.getTracks().forEach((track: MediaStreamTrack) => {\r\n track.addEventListener('ended', () => {\r\n if (this.recordingState === 'recording') {\r\n this.dispatchCustomEvent('error', {\r\n message: 'Microphone access was lost.',\r\n });\r\n this.stopRecording();\r\n }\r\n });\r\n });\r\n\r\n this._audioService = new AudioService(this._mediaStream);\r\n } catch (error) {\r\n this.dispatchCustomEvent('error', error);\r\n this.stopRecording();\r\n return;\r\n }\r\n\r\n // Initialize dictation service.\r\n try {\r\n this._dictationService = new DictationService(this._mediaStream, params);\r\n\r\n // Forward custom events from dictation service\r\n this._dictationService.addEventListener('error', e => {\r\n this.dispatchEvent(\r\n new CustomEvent('error', {\r\n detail: (e as CustomEvent).detail,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n this.stopRecording();\r\n });\r\n this._dictationService.addEventListener('stream-closed', () =>\r\n this.stopRecording(),\r\n );\r\n this._dictationService.addEventListener('transcript', e =>\r\n this.dispatchEvent(\r\n new CustomEvent('transcript', {\r\n detail: (e as CustomEvent).detail,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n ),\r\n );\r\n this._dictationService.addEventListener('command', e =>\r\n this.dispatchEvent(\r\n new CustomEvent('command', {\r\n detail: (e as CustomEvent).detail,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n ),\r\n );\r\n } catch (error) {\r\n this.dispatchCustomEvent('error', error);\r\n this.stopRecording();\r\n return;\r\n }\r\n\r\n try {\r\n this._dictationService?.startRecording();\r\n } catch (error) {\r\n this.dispatchEvent(\r\n new CustomEvent('error', {\r\n detail: error,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n this.stopRecording();\r\n return;\r\n }\r\n this._updateRecordingState('recording');\r\n\r\n // Update audio level visualization.\r\n this._visualiserInterval = window.setInterval(() => {\r\n const level = this._audioService\r\n ? this._audioService.getAudioLevel() * 3\r\n : 0;\r\n this.dispatchCustomEvent('audio-level-changed', { audioLevel: level });\r\n }, 150);\r\n }\r\n\r\n async stopRecording() {\r\n this._updateRecordingState('stopping');\r\n if (this._visualiserInterval) {\r\n clearInterval(this._visualiserInterval);\r\n this._visualiserInterval = undefined;\r\n }\r\n if (this._mediaStream) {\r\n this._mediaStream.getTracks().forEach(track => track.stop());\r\n }\r\n this.dispatchCustomEvent('audio-level-changed', { audioLevel: 0 });\r\n await this._dictationService?.stopRecording();\r\n this._updateRecordingState('stopped');\r\n }\r\n\r\n private _updateRecordingState(state: RecordingState) {\r\n this.recordingState = state;\r\n this.dispatchEvent(\r\n new CustomEvent('recording-state-changed', {\r\n detail: { state },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"RecorderManager.js","sourceRoot":"","sources":["../src/RecorderManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,MAAM,OAAO,eAAgB,SAAQ,WAAW;IAe9C;QACE,KAAK,EAAE,CAAC;QAfH,YAAO,GAAsB,EAAE,CAAC;QAIhC,mBAAc,GAAmB,SAAS,CAAC;QAE1C,iBAAY,GAAuB,IAAI,CAAC;QAExC,kBAAa,GAAwB,IAAI,CAAC;QAE1C,sBAAiB,GAA4B,IAAI,CAAC;QAMxD,SAAS,CAAC,YAAY,CAAC,gBAAgB,CACrC,cAAc,EACd,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CACpC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC;QACtC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC,aAAa,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;IACxE,CAAC;IAEO,mBAAmB,CAAC,SAAiB,EAAE,MAAgB;QAC7D,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,SAAS,EAAE;YACzB,MAAM;YACN,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC;QACtC,IACE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAChB,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,cAAc,EAAE,QAAQ,CAC5D,EACD,CAAC;YACD,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC,aAAa,CAAC;QACrD,CAAC;QACD,IAAI,CAAC,mBAAmB,CAAC,2BAA2B,EAAE;YACpD,OAAO,EAAE,cAAc,CAAC,OAAO;YAC/B,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,aAAa;SACpE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,MAIpB;QACC,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAE3C,IAAI,CAAC;YACH,IAAI,CAAC,YAAY,GAAG,MAAM,cAAc,CACtC,MAAM,CAAC,kBAAkB;gBACvB,CAAC,CAAC,eAAe;gBACjB,CAAC,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAClC,CAAC;YAEF,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAuB,EAAE,EAAE;gBAChE,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;oBACnC,IAAI,IAAI,CAAC,cAAc,KAAK,WAAW,EAAE,CAAC;wBACxC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE;4BAChC,OAAO,EAAE,6BAA6B;yBACvC,CAAC,CAAC;wBACH,IAAI,CAAC,aAAa,EAAE,CAAC;oBACvB,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,aAAa,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,gCAAgC;QAChC,IAAI,CAAC;YACH,IAAI,CAAC,iBAAiB,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YAEzE,+CAA+C;YAC/C,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE;gBACnD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,OAAO,EAAE;oBACvB,MAAM,EAAG,CAAiB,CAAC,MAAM;oBACjC,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,IAAI;iBACf,CAAC,CACH,CAAC;gBACF,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,eAAe,EAAE,GAAG,EAAE,CAC5D,IAAI,CAAC,aAAa,EAAE,CACrB,CAAC;YACF,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,CACxD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,YAAY,EAAE;gBAC5B,MAAM,EAAG,CAAiB,CAAC,MAAM;gBACjC,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;aACf,CAAC,CACH,CACF,CAAC;YACF,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CACrD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,SAAS,EAAE;gBACzB,MAAM,EAAG,CAAiB,CAAC,MAAM;gBACjC,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;aACf,CAAC,CACH,CACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,iBAAiB,EAAE,cAAc,EAAE,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,OAAO,EAAE;gBACvB,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;aACf,CAAC,CACH,CAAC;YACF,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAExC,oCAAoC;QACpC,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;YACjD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa;gBAC9B,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,EAAE,GAAG,CAAC;gBACxC,CAAC,CAAC,CAAC,CAAC;YACN,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QACzE,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,aAAa,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACxC,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;QACvC,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;QACnE,MAAM,IAAI,CAAC,iBAAiB,EAAE,aAAa,EAAE,CAAC;QAC9C,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IAEO,qBAAqB,CAAC,KAAqB;QACjD,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,yBAAyB,EAAE;YACzC,MAAM,EAAE,EAAE,KAAK,EAAE;YACjB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { getAudioDevices, getMediaStream } from './utils.js';\nimport { AudioService } from './audioService.js';\nimport { DictationService } from './DictationService.js';\nimport type { DictationConfig, RecordingState, ServerConfig } from './types.js';\n\nexport class RecorderManager extends EventTarget {\n public devices: MediaDeviceInfo[] = [];\n\n public selectedDevice: MediaDeviceInfo | undefined;\n\n public recordingState: RecordingState = 'stopped';\n\n private _mediaStream: MediaStream | null = null;\n\n private _audioService: AudioService | null = null;\n\n private _dictationService: DictationService | null = null;\n\n private _visualiserInterval?: number;\n\n constructor() {\n super();\n navigator.mediaDevices.addEventListener(\n 'devicechange',\n this.handleDevicesChange.bind(this),\n );\n }\n\n async initialize() {\n const deviceResponse = await getAudioDevices();\n this.devices = deviceResponse.devices;\n this.selectedDevice = deviceResponse.defaultDevice;\n return { devices: this.devices, selectedDevice: this.selectedDevice };\n }\n\n private dispatchCustomEvent(eventName: string, detail?: unknown): void {\n this.dispatchEvent(\n new CustomEvent(eventName, {\n detail,\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private async handleDevicesChange() {\n const deviceResponse = await getAudioDevices();\n this.devices = deviceResponse.devices;\n if (\n !this.devices.find(\n device => device.deviceId === this.selectedDevice?.deviceId,\n )\n ) {\n this.selectedDevice = deviceResponse.defaultDevice;\n }\n this.dispatchCustomEvent('recording-devices-changed', {\n devices: deviceResponse.devices,\n selectedDevice: this.selectedDevice || deviceResponse.defaultDevice,\n });\n }\n\n async startRecording(params: {\n dictationConfig: DictationConfig;\n serverConfig: ServerConfig;\n debug_displayAudio?: boolean;\n }): Promise<void> {\n this._updateRecordingState('initializing');\n\n try {\n this._mediaStream = await getMediaStream(\n params.debug_displayAudio\n ? 'display_audio'\n : this.selectedDevice?.deviceId,\n );\n\n this._mediaStream.getTracks().forEach((track: MediaStreamTrack) => {\n track.addEventListener('ended', () => {\n if (this.recordingState === 'recording') {\n this.dispatchCustomEvent('error', {\n message: 'Microphone access was lost.',\n });\n this.stopRecording();\n }\n });\n });\n\n this._audioService = new AudioService(this._mediaStream);\n } catch (error) {\n this.dispatchCustomEvent('error', error);\n this.stopRecording();\n return;\n }\n\n // Initialize dictation service.\n try {\n this._dictationService = new DictationService(this._mediaStream, params);\n\n // Forward custom events from dictation service\n this._dictationService.addEventListener('error', e => {\n this.dispatchEvent(\n new CustomEvent('error', {\n detail: (e as CustomEvent).detail,\n bubbles: true,\n composed: true,\n }),\n );\n this.stopRecording();\n });\n this._dictationService.addEventListener('stream-closed', () =>\n this.stopRecording(),\n );\n this._dictationService.addEventListener('transcript', e =>\n this.dispatchEvent(\n new CustomEvent('transcript', {\n detail: (e as CustomEvent).detail,\n bubbles: true,\n composed: true,\n }),\n ),\n );\n this._dictationService.addEventListener('command', e =>\n this.dispatchEvent(\n new CustomEvent('command', {\n detail: (e as CustomEvent).detail,\n bubbles: true,\n composed: true,\n }),\n ),\n );\n } catch (error) {\n this.dispatchCustomEvent('error', error);\n this.stopRecording();\n return;\n }\n\n try {\n this._dictationService?.startRecording();\n } catch (error) {\n this.dispatchEvent(\n new CustomEvent('error', {\n detail: error,\n bubbles: true,\n composed: true,\n }),\n );\n this.stopRecording();\n return;\n }\n this._updateRecordingState('recording');\n\n // Update audio level visualization.\n this._visualiserInterval = window.setInterval(() => {\n const level = this._audioService\n ? this._audioService.getAudioLevel() * 3\n : 0;\n this.dispatchCustomEvent('audio-level-changed', { audioLevel: level });\n }, 150);\n }\n\n async stopRecording() {\n this._updateRecordingState('stopping');\n if (this._visualiserInterval) {\n clearInterval(this._visualiserInterval);\n this._visualiserInterval = undefined;\n }\n if (this._mediaStream) {\n this._mediaStream.getTracks().forEach(track => track.stop());\n }\n this.dispatchCustomEvent('audio-level-changed', { audioLevel: 0 });\n await this._dictationService?.stopRecording();\n this._updateRecordingState('stopped');\n }\n\n private _updateRecordingState(state: RecordingState) {\n this.recordingState = state;\n this.dispatchEvent(\n new CustomEvent('recording-state-changed', {\n detail: { state },\n bubbles: true,\n composed: true,\n }),\n );\n }\n}\n"]}
|
package/dist/bundle.js
CHANGED
|
@@ -659,7 +659,7 @@ function decodeToken(token) {
|
|
|
659
659
|
return {
|
|
660
660
|
environment: match[2],
|
|
661
661
|
tenant: match[3],
|
|
662
|
-
token
|
|
662
|
+
accessToken: token
|
|
663
663
|
};
|
|
664
664
|
}
|
|
665
665
|
}
|
|
@@ -707,15 +707,11 @@ var AudioService = class {
|
|
|
707
707
|
|
|
708
708
|
// dist/DictationService.js
|
|
709
709
|
var DictationService = class extends EventTarget {
|
|
710
|
-
constructor(mediaStream, { dictationConfig,
|
|
710
|
+
constructor(mediaStream, { dictationConfig, serverConfig }) {
|
|
711
711
|
super();
|
|
712
712
|
this.mediaRecorder = new MediaRecorder(mediaStream);
|
|
713
|
-
this.
|
|
713
|
+
this.serverConfig = serverConfig;
|
|
714
714
|
this.dictationConfig = dictationConfig;
|
|
715
|
-
const config = decodeToken(this.authToken);
|
|
716
|
-
if (!config) {
|
|
717
|
-
throw new Error("Invalid token");
|
|
718
|
-
}
|
|
719
715
|
this.mediaRecorder.ondataavailable = (event) => {
|
|
720
716
|
if (this.webSocket?.readyState === WebSocket.OPEN) {
|
|
721
717
|
this.webSocket.send(event.data);
|
|
@@ -730,8 +726,7 @@ var DictationService = class extends EventTarget {
|
|
|
730
726
|
}));
|
|
731
727
|
}
|
|
732
728
|
startRecording() {
|
|
733
|
-
|
|
734
|
-
if (!serverConfig) {
|
|
729
|
+
if (!this.serverConfig) {
|
|
735
730
|
this.dispatchEvent(new CustomEvent("error", {
|
|
736
731
|
detail: "Invalid token",
|
|
737
732
|
bubbles: true,
|
|
@@ -739,7 +734,7 @@ var DictationService = class extends EventTarget {
|
|
|
739
734
|
}));
|
|
740
735
|
return;
|
|
741
736
|
}
|
|
742
|
-
const url = `wss://api.${serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${serverConfig.tenant}&token=Bearer%20${this.
|
|
737
|
+
const url = `wss://api.${this.serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${this.serverConfig.tenant}&token=Bearer%20${this.serverConfig.accessToken}`;
|
|
743
738
|
this.webSocket = new WebSocket(url);
|
|
744
739
|
this.webSocket.onopen = () => {
|
|
745
740
|
this.webSocket.send(JSON.stringify({
|
|
@@ -1019,9 +1014,9 @@ var DEFAULT_DICTATION_CONFIG = {
|
|
|
1019
1014
|
// dist/styles/callout.js
|
|
1020
1015
|
var CalloutStyles = i`
|
|
1021
1016
|
.callout {
|
|
1022
|
-
background: var(--callout-
|
|
1023
|
-
border: 1px solid var(--callout-
|
|
1024
|
-
color: var(--callout-
|
|
1017
|
+
background: var(--callout-info-background);
|
|
1018
|
+
border: 1px solid var(--callout-info-border);
|
|
1019
|
+
color: var(--callout-info-text);
|
|
1025
1020
|
padding: 8px;
|
|
1026
1021
|
border-radius: var(--card-inner-border-radius);
|
|
1027
1022
|
display: flex;
|
|
@@ -1030,15 +1025,15 @@ var CalloutStyles = i`
|
|
|
1030
1025
|
align-items: center;
|
|
1031
1026
|
max-width: 100%;
|
|
1032
1027
|
height: fit-content;
|
|
1033
|
-
&.
|
|
1034
|
-
background: var(--callout-
|
|
1035
|
-
border: 1px solid var(--callout-
|
|
1036
|
-
color: var(--callout-
|
|
1028
|
+
&.error {
|
|
1029
|
+
background: var(--callout-error-background);
|
|
1030
|
+
border: 1px solid var(--callout-error-border);
|
|
1031
|
+
color: var(--callout-warn-text);
|
|
1037
1032
|
}
|
|
1038
|
-
&.
|
|
1039
|
-
background: var(--callout-
|
|
1040
|
-
border: 1px solid var(--callout-
|
|
1041
|
-
color: var(--callout-
|
|
1033
|
+
&.warn {
|
|
1034
|
+
background: var(--callout-warn-background);
|
|
1035
|
+
border: 1px solid var(--callout-warn-border);
|
|
1036
|
+
color: var(--callout-warn-text);
|
|
1042
1037
|
}
|
|
1043
1038
|
&.small {
|
|
1044
1039
|
width: 100%;
|
|
@@ -1098,7 +1093,7 @@ var SettingsMenu = class SettingsMenu2 extends r4 {
|
|
|
1098
1093
|
<div id="settings-popover" popover>
|
|
1099
1094
|
<div class="settings-wrapper">
|
|
1100
1095
|
${this.settingsDisabled ? x`
|
|
1101
|
-
<div class="callout
|
|
1096
|
+
<div class="callout warn">
|
|
1102
1097
|
Recording is in progress. Stop recording to change settings.
|
|
1103
1098
|
</div>
|
|
1104
1099
|
` : ""}
|
|
@@ -1175,10 +1170,9 @@ SettingsMenu.styles = [
|
|
|
1175
1170
|
width: 100%;
|
|
1176
1171
|
min-width: 200px;
|
|
1177
1172
|
position-anchor: --settings_popover_btn;
|
|
1178
|
-
position-area: bottom;
|
|
1173
|
+
position-area: bottom span-right;
|
|
1179
1174
|
position-visibility: always;
|
|
1180
|
-
|
|
1181
|
-
transform: translateX(40%);
|
|
1175
|
+
position-try-fallbacks: flip-inline;
|
|
1182
1176
|
overflow-x: hidden;
|
|
1183
1177
|
}
|
|
1184
1178
|
.settings-wrapper {
|
|
@@ -1423,69 +1417,48 @@ IconLoadingSpinner = __decorate3([
|
|
|
1423
1417
|
// dist/styles/theme.js
|
|
1424
1418
|
var ThemeStyles = i`
|
|
1425
1419
|
:host {
|
|
1420
|
+
color-scheme: light dark;
|
|
1426
1421
|
/* Component Defaults */
|
|
1427
1422
|
--component-font-family: 'Segoe UI', Roboto, sans-serif;
|
|
1428
|
-
--component-text-color: #333;
|
|
1423
|
+
--component-text-color: light-dark(#333, #eee);
|
|
1429
1424
|
|
|
1430
1425
|
/* Card Defaults */
|
|
1431
|
-
--card-background: #fff;
|
|
1432
|
-
--card-border-color: #ddd;
|
|
1426
|
+
--card-background: light-dark(#fff, #333);
|
|
1427
|
+
--card-border-color: light-dark(#ddd, #555);
|
|
1433
1428
|
--card-padding: 4px;
|
|
1434
1429
|
--card-border-radius: 8px;
|
|
1435
1430
|
--card-inner-border-radius: 6px;
|
|
1436
1431
|
--card-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
1437
1432
|
|
|
1438
1433
|
/* Actions Defaults */
|
|
1439
|
-
--action-plain-border-color: #ccc;
|
|
1440
|
-
--action-plain-background-hover: #ddd;
|
|
1434
|
+
--action-plain-border-color: light-dark(#ccc, #555);
|
|
1435
|
+
--action-plain-background-hover: light-dark(#ddd, #444);
|
|
1441
1436
|
|
|
1442
|
-
--action-accent-background: #007bff;
|
|
1443
|
-
--action-accent-background-hover: #0056b3;
|
|
1437
|
+
--action-accent-background: light-dark(#007bff, #0056b3);
|
|
1438
|
+
--action-accent-background-hover: light-dark(#0056b3, #003d80);
|
|
1444
1439
|
--action-accent-text-color: #fff;
|
|
1445
1440
|
|
|
1446
|
-
--action-red-background: #dc3545;
|
|
1447
|
-
--action-red-background-hover: #bd2130;
|
|
1441
|
+
--action-red-background: light-dark(#dc3545, #bd2130);
|
|
1442
|
+
--action-red-background-hover: light-dark(#bd2130, #a71c24);
|
|
1448
1443
|
--action-red-text-color: #fff;
|
|
1449
1444
|
|
|
1450
1445
|
/* Callout Defaults */
|
|
1451
|
-
--callout-
|
|
1452
|
-
--callout-
|
|
1453
|
-
--callout-
|
|
1446
|
+
--callout-info-background: light-dark(#007bff33, #0056b333);
|
|
1447
|
+
--callout-info-border: light-dark(#007bff99, #0056b399);
|
|
1448
|
+
--callout-info-text: light-dark(#007bff, #0056b3);
|
|
1454
1449
|
|
|
1455
|
-
--callout-
|
|
1456
|
-
--callout-
|
|
1457
|
-
--callout-
|
|
1450
|
+
--callout-error-background: light-dark(#dc354533, #bd213033);
|
|
1451
|
+
--callout-error-border: light-dark(#dc354599, #bd213099);
|
|
1452
|
+
--callout-error-text: light-dark(#dc3545, #bd2130);
|
|
1458
1453
|
|
|
1459
|
-
--callout-
|
|
1460
|
-
--callout-
|
|
1461
|
-
--callout-
|
|
1454
|
+
--callout-warn-background: light-dark(#fd7e1433, #e06c1233);
|
|
1455
|
+
--callout-warn-border: light-dark(#fd7e1499, #e06c1299);
|
|
1456
|
+
--callout-warn-text: light-dark(#fd7e14, #e06c12);
|
|
1462
1457
|
|
|
1463
1458
|
/* Visualiser Defaults */
|
|
1464
|
-
--visualiser-background: #e0e0e0;
|
|
1465
|
-
--visualiser-level-color: #28a745;
|
|
1459
|
+
--visualiser-background: light-dark(#e0e0e0, #fff);
|
|
1466
1460
|
}
|
|
1467
1461
|
|
|
1468
|
-
@media (prefers-color-scheme: dark) {
|
|
1469
|
-
:host {
|
|
1470
|
-
/* Component Dark */
|
|
1471
|
-
--component-text-color: #eee;
|
|
1472
|
-
|
|
1473
|
-
/* Card Dark */
|
|
1474
|
-
--card-background: #333;
|
|
1475
|
-
--card-border-color: #555;
|
|
1476
|
-
|
|
1477
|
-
/* Actions Dark */
|
|
1478
|
-
--action-plain-border-color: #555;
|
|
1479
|
-
--action-plain-background: #333;
|
|
1480
|
-
--action-plain-background-hover: #444;
|
|
1481
|
-
|
|
1482
|
-
--action-accent-background: #0056b3;
|
|
1483
|
-
--action-accent-background-hover: #003d80;
|
|
1484
|
-
|
|
1485
|
-
/* Visualiser Dark */
|
|
1486
|
-
--visualiser-background: #fff;
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
1462
|
:host {
|
|
1490
1463
|
box-sizing: border-box;
|
|
1491
1464
|
font-family: var(--component-font-family);
|
|
@@ -1611,6 +1584,14 @@ var CortiDictation = class extends r4 {
|
|
|
1611
1584
|
toggleRecording() {
|
|
1612
1585
|
this._toggleRecording();
|
|
1613
1586
|
}
|
|
1587
|
+
setAccessToken(token) {
|
|
1588
|
+
const decoded = decodeToken(token);
|
|
1589
|
+
if (!decoded) {
|
|
1590
|
+
throw new Error("Invalid token");
|
|
1591
|
+
}
|
|
1592
|
+
this._serverConfig = decoded;
|
|
1593
|
+
return decoded;
|
|
1594
|
+
}
|
|
1614
1595
|
get selectedDevice() {
|
|
1615
1596
|
return this.recorderManager.selectedDevice || null;
|
|
1616
1597
|
}
|
|
@@ -1623,25 +1604,25 @@ var CortiDictation = class extends r4 {
|
|
|
1623
1604
|
async setRecordingDevice(device) {
|
|
1624
1605
|
this.recorderManager.selectedDevice = device;
|
|
1625
1606
|
this._selectedDevice = device;
|
|
1626
|
-
if (!this.
|
|
1607
|
+
if (!this._serverConfig)
|
|
1627
1608
|
return;
|
|
1628
1609
|
if (this._recordingState === "recording") {
|
|
1629
1610
|
await this.recorderManager.stopRecording();
|
|
1630
1611
|
await this.recorderManager.startRecording({
|
|
1631
1612
|
dictationConfig: this.dictationConfig,
|
|
1632
|
-
|
|
1613
|
+
serverConfig: this._serverConfig
|
|
1633
1614
|
});
|
|
1634
1615
|
}
|
|
1635
1616
|
}
|
|
1636
1617
|
_toggleRecording() {
|
|
1637
|
-
if (!this.
|
|
1618
|
+
if (!this._serverConfig)
|
|
1638
1619
|
return;
|
|
1639
1620
|
if (this._recordingState === "recording") {
|
|
1640
1621
|
this.recorderManager.stopRecording();
|
|
1641
1622
|
} else if (this._recordingState === "stopped") {
|
|
1642
1623
|
this.recorderManager.startRecording({
|
|
1643
1624
|
dictationConfig: this.dictationConfig,
|
|
1644
|
-
|
|
1625
|
+
serverConfig: this._serverConfig,
|
|
1645
1626
|
debug_displayAudio: this.debug_displayAudio
|
|
1646
1627
|
});
|
|
1647
1628
|
}
|
|
@@ -1652,14 +1633,6 @@ var CortiDictation = class extends r4 {
|
|
|
1652
1633
|
this.setRecordingDevice(customEvent.detail.selectedDevice);
|
|
1653
1634
|
}
|
|
1654
1635
|
render() {
|
|
1655
|
-
const isConfigured = this.authToken;
|
|
1656
|
-
if (!isConfigured) {
|
|
1657
|
-
return x`
|
|
1658
|
-
<div class="wrapper">
|
|
1659
|
-
<div class="callout red small">No Auth Token</div>
|
|
1660
|
-
</div>
|
|
1661
|
-
`;
|
|
1662
|
-
}
|
|
1663
1636
|
const isLoading = this._recordingState === "initializing" || this._recordingState === "stopping";
|
|
1664
1637
|
const isRecording = this._recordingState === "recording";
|
|
1665
1638
|
return x`
|
|
@@ -1688,12 +1661,12 @@ CortiDictation.styles = [buttons_default, theme_default, ComponentStyles_default
|
|
|
1688
1661
|
__decorate4([
|
|
1689
1662
|
n4({ type: Object })
|
|
1690
1663
|
], CortiDictation.prototype, "dictationConfig", void 0);
|
|
1691
|
-
__decorate4([
|
|
1692
|
-
n4({ type: String })
|
|
1693
|
-
], CortiDictation.prototype, "authToken", void 0);
|
|
1694
1664
|
__decorate4([
|
|
1695
1665
|
n4({ type: Boolean })
|
|
1696
1666
|
], CortiDictation.prototype, "debug_displayAudio", void 0);
|
|
1667
|
+
__decorate4([
|
|
1668
|
+
r6()
|
|
1669
|
+
], CortiDictation.prototype, "_serverConfig", void 0);
|
|
1697
1670
|
__decorate4([
|
|
1698
1671
|
r6()
|
|
1699
1672
|
], CortiDictation.prototype, "_audioLevel", void 0);
|
|
@@ -56,7 +56,7 @@ let SettingsMenu = class SettingsMenu extends LitElement {
|
|
|
56
56
|
<div class="settings-wrapper">
|
|
57
57
|
${this.settingsDisabled
|
|
58
58
|
? html `
|
|
59
|
-
<div class="callout
|
|
59
|
+
<div class="callout warn">
|
|
60
60
|
Recording is in progress. Stop recording to change settings.
|
|
61
61
|
</div>
|
|
62
62
|
`
|
|
@@ -134,10 +134,9 @@ SettingsMenu.styles = [
|
|
|
134
134
|
width: 100%;
|
|
135
135
|
min-width: 200px;
|
|
136
136
|
position-anchor: --settings_popover_btn;
|
|
137
|
-
position-area: bottom;
|
|
137
|
+
position-area: bottom span-right;
|
|
138
138
|
position-visibility: always;
|
|
139
|
-
|
|
140
|
-
transform: translateX(40%);
|
|
139
|
+
position-try-fallbacks: flip-inline;
|
|
141
140
|
overflow-x: hidden;
|
|
142
141
|
}
|
|
143
142
|
.settings-wrapper {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-menu.js","sourceRoot":"","sources":["../../src/components/settings-menu.ts"],"names":[],"mappings":";;;;;;AAAA,kBAAkB;AAClB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAkC,MAAM,KAAK,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,YAAY,MAAM,sBAAsB,CAAC;AAChD,OAAO,YAAY,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,aAAa,MAAM,sBAAsB,CAAC;AAG1C,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAa1C;QACE,KAAK,EAAE,CAAC;QATV,qBAAgB,GAAW,EAAE,CAAC;QAG9B,qBAAgB,GAAY,KAAK,CAAC;QAG1B,aAAQ,GAAsB,EAAE,CAAC;QAIvC,SAAS,CAAC,YAAY,CAAC,gBAAgB,CACrC,cAAc,EACd,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CACpC,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,KAAK,CAAC,iBAAiB;QACrB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;IACzC,CAAC;
|
|
1
|
+
{"version":3,"file":"settings-menu.js","sourceRoot":"","sources":["../../src/components/settings-menu.ts"],"names":[],"mappings":"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","sourcesContent":["// mic-selector.ts\nimport { LitElement, html, css, TemplateResult, CSSResultGroup } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\n\nimport ButtonStyles from '../styles/buttons.js';\nimport SelectStyles from '../styles/select.js';\nimport { LANGUAGES_SUPPORTED } from '../constants.js';\nimport { getAudioDevices, getLanguageName } from '../utils.js';\nimport CalloutStyles from '../styles/callout.js';\n\n@customElement('settings-menu')\nexport class SettingsMenu extends LitElement {\n @property({ type: String })\n selectedDevice: MediaDeviceInfo | undefined;\n\n @property({ type: String })\n selectedLanguage: string = '';\n\n @property({ type: Boolean })\n settingsDisabled: boolean = false;\n\n @state()\n private _devices: MediaDeviceInfo[] = [];\n\n constructor() {\n super();\n navigator.mediaDevices.addEventListener(\n 'devicechange',\n this.handleDevicesChange.bind(this),\n );\n }\n\n // on load, get the available devices\n async connectedCallback(): Promise<void> {\n super.connectedCallback();\n const deviceResponse = await getAudioDevices();\n this._devices = deviceResponse.devices;\n }\n\n private async handleDevicesChange() {\n const deviceResponse = await getAudioDevices();\n this._devices = deviceResponse.devices;\n }\n\n static styles: CSSResultGroup = [\n css`\n :host {\n display: block;\n font-family: var(--component-font-family);\n }\n /* Retain the anchor-name styling for this component */\n #settings-popover-button {\n anchor-name: --settings_popover_btn;\n }\n [popover] {\n margin: 0;\n padding: 16px;\n border: 0;\n background: var(--card-background);\n border: 1px solid var(--card-border-color);\n border-radius: var(--card-border-radius);\n box-shadow: var(--card-box-shadow);\n z-index: 1000;\n max-width: 260px;\n width: 100%;\n min-width: 200px;\n position-anchor: --settings_popover_btn;\n position-area: bottom span-right;\n position-visibility: always;\n position-try-fallbacks: flip-inline;\n overflow-x: hidden;\n }\n .settings-wrapper {\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n `,\n ButtonStyles,\n SelectStyles,\n CalloutStyles,\n ];\n\n private _selectDevice(deviceId: string): void {\n // Find the device object\n const device = this._devices.find(d => d.deviceId === deviceId);\n if (!device) {\n return;\n }\n this.selectedDevice = device;\n this.dispatchEvent(\n new CustomEvent('recording-devices-changed', {\n detail: {\n devices: this._devices,\n selectedDevice: device,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n render(): TemplateResult {\n return html`\n <div class=\"mic-selector\">\n <button id=\"settings-popover-button\" popovertarget=\"settings-popover\">\n <icon-settings></icon-settings>\n </button>\n <div id=\"settings-popover\" popover>\n <div class=\"settings-wrapper\">\n ${this.settingsDisabled\n ? html`\n <div class=\"callout warn\">\n Recording is in progress. Stop recording to change settings.\n </div>\n `\n : ''}\n <div class=\"form-group\">\n <label id=\"device-select-label\" for=\"device-select\">\n Recording Device\n </label>\n <select\n id=\"device-select\"\n aria-labelledby=\"device-select-label\"\n @change=${(e: Event) => {\n this._selectDevice((e.target as HTMLSelectElement).value);\n }}\n ?disabled=${this.settingsDisabled}\n >\n ${this._devices.map(\n device => html`\n <option\n value=${device.deviceId}\n ?selected=${this.selectedDevice === device}\n >\n ${device.label || 'Unknown Device'}\n </option>\n `,\n )}\n </select>\n </div>\n <div class=\"form-group\">\n <label id=\"language-select-label\" for=\"language-select\">\n Dictation Language\n </label>\n <select\n id=\"language-select\"\n aria-labelledby=\"language-select-label\"\n @change=${(e: Event) => {\n this._selectDevice((e.target as HTMLSelectElement).value);\n }}\n ?disabled=${this.settingsDisabled}\n >\n ${LANGUAGES_SUPPORTED.map(\n language => html`\n <option\n value=${language}\n ?selected=${this.selectedLanguage === language}\n >\n ${getLanguageName(language)}\n </option>\n `,\n )}\n </select>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'settings-menu': SettingsMenu;\n }\n}\n"]}
|
package/dist/constants.js
CHANGED
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,wBAAwB,GAAoB;IACvD,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,IAAI;IACpB,iBAAiB,EAAE,IAAI;IACvB,oBAAoB,EAAE,IAAI;IAC1B,KAAK,EAAE,QAAQ;CAChB,CAAC","sourcesContent":["import { DictationConfig } from './types.js';\
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,wBAAwB,GAAoB;IACvD,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,IAAI;IACpB,iBAAiB,EAAE,IAAI;IACvB,oBAAoB,EAAE,IAAI;IAC1B,KAAK,EAAE,QAAQ;CAChB,CAAC","sourcesContent":["import { DictationConfig } from './types.js';\n\nexport const LANGUAGES_SUPPORTED = ['en', 'da'];\nexport const DEFAULT_DICTATION_CONFIG: DictationConfig = {\n primaryLanguage: 'en',\n interimResults: true,\n spokenPunctuation: true,\n automaticPunctuation: true,\n model: 'others',\n};\n"]}
|
package/dist/styles/callout.js
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
const CalloutStyles = css `
|
|
3
|
-
.callout {
|
|
4
|
-
background: var(--callout-
|
|
5
|
-
border: 1px solid var(--callout-
|
|
6
|
-
color: var(--callout-
|
|
7
|
-
padding: 8px;
|
|
8
|
-
border-radius: var(--card-inner-border-radius);
|
|
9
|
-
display: flex;
|
|
10
|
-
font-size: 0.9rem;
|
|
11
|
-
gap: 8px;
|
|
12
|
-
align-items: center;
|
|
13
|
-
max-width: 100%;
|
|
14
|
-
height: fit-content;
|
|
15
|
-
&.
|
|
16
|
-
background: var(--callout-
|
|
17
|
-
border: 1px solid var(--callout-
|
|
18
|
-
color: var(--callout-
|
|
19
|
-
}
|
|
20
|
-
&.
|
|
21
|
-
background: var(--callout-
|
|
22
|
-
border: 1px solid var(--callout-
|
|
23
|
-
color: var(--callout-
|
|
24
|
-
}
|
|
25
|
-
&.small {
|
|
26
|
-
width: 100%;
|
|
27
|
-
padding: 6px;
|
|
28
|
-
font-size: 0.7rem;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
2
|
+
const CalloutStyles = css `
|
|
3
|
+
.callout {
|
|
4
|
+
background: var(--callout-info-background);
|
|
5
|
+
border: 1px solid var(--callout-info-border);
|
|
6
|
+
color: var(--callout-info-text);
|
|
7
|
+
padding: 8px;
|
|
8
|
+
border-radius: var(--card-inner-border-radius);
|
|
9
|
+
display: flex;
|
|
10
|
+
font-size: 0.9rem;
|
|
11
|
+
gap: 8px;
|
|
12
|
+
align-items: center;
|
|
13
|
+
max-width: 100%;
|
|
14
|
+
height: fit-content;
|
|
15
|
+
&.error {
|
|
16
|
+
background: var(--callout-error-background);
|
|
17
|
+
border: 1px solid var(--callout-error-border);
|
|
18
|
+
color: var(--callout-warn-text);
|
|
19
|
+
}
|
|
20
|
+
&.warn {
|
|
21
|
+
background: var(--callout-warn-background);
|
|
22
|
+
border: 1px solid var(--callout-warn-border);
|
|
23
|
+
color: var(--callout-warn-text);
|
|
24
|
+
}
|
|
25
|
+
&.small {
|
|
26
|
+
width: 100%;
|
|
27
|
+
padding: 6px;
|
|
28
|
+
font-size: 0.7rem;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
31
|
`;
|
|
32
32
|
export default CalloutStyles;
|
|
33
33
|
//# sourceMappingURL=callout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callout.js","sourceRoot":"","sources":["../../src/styles/callout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,aAAa,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BxB,CAAC;AAEF,eAAe,aAAa,CAAC","sourcesContent":["import { css } from 'lit';\
|
|
1
|
+
{"version":3,"file":"callout.js","sourceRoot":"","sources":["../../src/styles/callout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,aAAa,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BxB,CAAC;AAEF,eAAe,aAAa,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst CalloutStyles = css`\n .callout {\n background: var(--callout-info-background);\n border: 1px solid var(--callout-info-border);\n color: var(--callout-info-text);\n padding: 8px;\n border-radius: var(--card-inner-border-radius);\n display: flex;\n font-size: 0.9rem;\n gap: 8px;\n align-items: center;\n max-width: 100%;\n height: fit-content;\n &.error {\n background: var(--callout-error-background);\n border: 1px solid var(--callout-error-border);\n color: var(--callout-warn-text);\n }\n &.warn {\n background: var(--callout-warn-background);\n border: 1px solid var(--callout-warn-border);\n color: var(--callout-warn-text);\n }\n &.small {\n width: 100%;\n padding: 6px;\n font-size: 0.7rem;\n }\n }\n`;\n\nexport default CalloutStyles;\n"]}
|
package/dist/styles/theme.js
CHANGED
|
@@ -1,69 +1,48 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
2
|
const ThemeStyles = css `
|
|
3
3
|
:host {
|
|
4
|
+
color-scheme: light dark;
|
|
4
5
|
/* Component Defaults */
|
|
5
6
|
--component-font-family: 'Segoe UI', Roboto, sans-serif;
|
|
6
|
-
--component-text-color: #333;
|
|
7
|
+
--component-text-color: light-dark(#333, #eee);
|
|
7
8
|
|
|
8
9
|
/* Card Defaults */
|
|
9
|
-
--card-background: #fff;
|
|
10
|
-
--card-border-color: #ddd;
|
|
10
|
+
--card-background: light-dark(#fff, #333);
|
|
11
|
+
--card-border-color: light-dark(#ddd, #555);
|
|
11
12
|
--card-padding: 4px;
|
|
12
13
|
--card-border-radius: 8px;
|
|
13
14
|
--card-inner-border-radius: 6px;
|
|
14
15
|
--card-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
15
16
|
|
|
16
17
|
/* Actions Defaults */
|
|
17
|
-
--action-plain-border-color: #ccc;
|
|
18
|
-
--action-plain-background-hover: #ddd;
|
|
18
|
+
--action-plain-border-color: light-dark(#ccc, #555);
|
|
19
|
+
--action-plain-background-hover: light-dark(#ddd, #444);
|
|
19
20
|
|
|
20
|
-
--action-accent-background: #007bff;
|
|
21
|
-
--action-accent-background-hover: #0056b3;
|
|
21
|
+
--action-accent-background: light-dark(#007bff, #0056b3);
|
|
22
|
+
--action-accent-background-hover: light-dark(#0056b3, #003d80);
|
|
22
23
|
--action-accent-text-color: #fff;
|
|
23
24
|
|
|
24
|
-
--action-red-background: #dc3545;
|
|
25
|
-
--action-red-background-hover: #bd2130;
|
|
25
|
+
--action-red-background: light-dark(#dc3545, #bd2130);
|
|
26
|
+
--action-red-background-hover: light-dark(#bd2130, #a71c24);
|
|
26
27
|
--action-red-text-color: #fff;
|
|
27
28
|
|
|
28
29
|
/* Callout Defaults */
|
|
29
|
-
--callout-
|
|
30
|
-
--callout-
|
|
31
|
-
--callout-
|
|
30
|
+
--callout-info-background: light-dark(#007bff33, #0056b333);
|
|
31
|
+
--callout-info-border: light-dark(#007bff99, #0056b399);
|
|
32
|
+
--callout-info-text: light-dark(#007bff, #0056b3);
|
|
32
33
|
|
|
33
|
-
--callout-
|
|
34
|
-
--callout-
|
|
35
|
-
--callout-
|
|
34
|
+
--callout-error-background: light-dark(#dc354533, #bd213033);
|
|
35
|
+
--callout-error-border: light-dark(#dc354599, #bd213099);
|
|
36
|
+
--callout-error-text: light-dark(#dc3545, #bd2130);
|
|
36
37
|
|
|
37
|
-
--callout-
|
|
38
|
-
--callout-
|
|
39
|
-
--callout-
|
|
38
|
+
--callout-warn-background: light-dark(#fd7e1433, #e06c1233);
|
|
39
|
+
--callout-warn-border: light-dark(#fd7e1499, #e06c1299);
|
|
40
|
+
--callout-warn-text: light-dark(#fd7e14, #e06c12);
|
|
40
41
|
|
|
41
42
|
/* Visualiser Defaults */
|
|
42
|
-
--visualiser-background: #e0e0e0;
|
|
43
|
-
--visualiser-level-color: #28a745;
|
|
43
|
+
--visualiser-background: light-dark(#e0e0e0, #fff);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
@media (prefers-color-scheme: dark) {
|
|
47
|
-
:host {
|
|
48
|
-
/* Component Dark */
|
|
49
|
-
--component-text-color: #eee;
|
|
50
|
-
|
|
51
|
-
/* Card Dark */
|
|
52
|
-
--card-background: #333;
|
|
53
|
-
--card-border-color: #555;
|
|
54
|
-
|
|
55
|
-
/* Actions Dark */
|
|
56
|
-
--action-plain-border-color: #555;
|
|
57
|
-
--action-plain-background: #333;
|
|
58
|
-
--action-plain-background-hover: #444;
|
|
59
|
-
|
|
60
|
-
--action-accent-background: #0056b3;
|
|
61
|
-
--action-accent-background-hover: #003d80;
|
|
62
|
-
|
|
63
|
-
/* Visualiser Dark */
|
|
64
|
-
--visualiser-background: #fff;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
46
|
:host {
|
|
68
47
|
box-sizing: border-box;
|
|
69
48
|
font-family: var(--component-font-family);
|
package/dist/styles/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/styles/theme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,WAAW,GAAG,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/styles/theme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,WAAW,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDtB,CAAC;AAEF,eAAe,WAAW,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst ThemeStyles = css`\n :host {\n color-scheme: light dark;\n /* Component Defaults */\n --component-font-family: 'Segoe UI', Roboto, sans-serif;\n --component-text-color: light-dark(#333, #eee);\n\n /* Card Defaults */\n --card-background: light-dark(#fff, #333);\n --card-border-color: light-dark(#ddd, #555);\n --card-padding: 4px;\n --card-border-radius: 8px;\n --card-inner-border-radius: 6px;\n --card-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n\n /* Actions Defaults */\n --action-plain-border-color: light-dark(#ccc, #555);\n --action-plain-background-hover: light-dark(#ddd, #444);\n\n --action-accent-background: light-dark(#007bff, #0056b3);\n --action-accent-background-hover: light-dark(#0056b3, #003d80);\n --action-accent-text-color: #fff;\n\n --action-red-background: light-dark(#dc3545, #bd2130);\n --action-red-background-hover: light-dark(#bd2130, #a71c24);\n --action-red-text-color: #fff;\n\n /* Callout Defaults */\n --callout-info-background: light-dark(#007bff33, #0056b333);\n --callout-info-border: light-dark(#007bff99, #0056b399);\n --callout-info-text: light-dark(#007bff, #0056b3);\n\n --callout-error-background: light-dark(#dc354533, #bd213033);\n --callout-error-border: light-dark(#dc354599, #bd213099);\n --callout-error-text: light-dark(#dc3545, #bd2130);\n\n --callout-warn-background: light-dark(#fd7e1433, #e06c1233);\n --callout-warn-border: light-dark(#fd7e1499, #e06c1299);\n --callout-warn-text: light-dark(#fd7e14, #e06c12);\n\n /* Visualiser Defaults */\n --visualiser-background: light-dark(#e0e0e0, #fff);\n }\n\n :host {\n box-sizing: border-box;\n font-family: var(--component-font-family);\n color: var(--component-text-color);\n }\n`;\n\nexport default ThemeStyles;\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -19,8 +19,8 @@ export interface DictationConfig {
|
|
|
19
19
|
}
|
|
20
20
|
export type PartialDictationConfig = Partial<DictationConfig>;
|
|
21
21
|
export interface ServerConfig {
|
|
22
|
-
environment
|
|
23
|
-
tenant
|
|
24
|
-
|
|
22
|
+
environment: string;
|
|
23
|
+
tenant: string;
|
|
24
|
+
accessToken: string;
|
|
25
25
|
}
|
|
26
26
|
export {};
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type RecordingState =\n | 'initializing'\n | 'recording'\n | 'stopping'\n | 'stopped';\n\ninterface CommandVariable {\n key: string;\n type: 'enum' | 'string';\n enum?: string[];\n}\n\nexport interface Command {\n id: string;\n phrases: string[];\n variables?: CommandVariable[];\n}\n\nexport interface DictationConfig {\n primaryLanguage: string;\n interimResults: boolean;\n spokenPunctuation: boolean;\n automaticPunctuation: boolean;\n model: string;\n commands?: Command[];\n}\n\nexport type PartialDictationConfig = Partial<DictationConfig>;\n\nexport interface ServerConfig {\n environment
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type RecordingState =\n | 'initializing'\n | 'recording'\n | 'stopping'\n | 'stopped';\n\ninterface CommandVariable {\n key: string;\n type: 'enum' | 'string';\n enum?: string[];\n}\n\nexport interface Command {\n id: string;\n phrases: string[];\n variables?: CommandVariable[];\n}\n\nexport interface DictationConfig {\n primaryLanguage: string;\n interimResults: boolean;\n spokenPunctuation: boolean;\n automaticPunctuation: boolean;\n model: string;\n commands?: Command[];\n}\n\nexport type PartialDictationConfig = Partial<DictationConfig>;\n\nexport interface ServerConfig {\n environment: string;\n tenant: string;\n accessToken: string;\n}\n"]}
|
package/dist/utils.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export declare function getAudioDevices(): Promise<{
|
|
|
41
41
|
* @returns An object containing:
|
|
42
42
|
* - `environment`: The extracted environment from the issuer URL.
|
|
43
43
|
* - `tenant`: The extracted tenant from the issuer URL.
|
|
44
|
-
* - `
|
|
44
|
+
* - `accessToken`: The original token string.
|
|
45
45
|
* If the issuer URL doesn't match the expected format, the function returns the full decoded token details.
|
|
46
46
|
*
|
|
47
47
|
* @throws Will throw an error if:
|
|
@@ -53,6 +53,6 @@ export declare function getAudioDevices(): Promise<{
|
|
|
53
53
|
export declare function decodeToken(token: string): {
|
|
54
54
|
environment: string;
|
|
55
55
|
tenant: string;
|
|
56
|
-
|
|
56
|
+
accessToken: string;
|
|
57
57
|
} | undefined;
|
|
58
58
|
export declare function getMediaStream(deviceId?: string): Promise<MediaStream>;
|
package/dist/utils.js
CHANGED
|
@@ -86,7 +86,7 @@ export async function getAudioDevices() {
|
|
|
86
86
|
* @returns An object containing:
|
|
87
87
|
* - `environment`: The extracted environment from the issuer URL.
|
|
88
88
|
* - `tenant`: The extracted tenant from the issuer URL.
|
|
89
|
-
* - `
|
|
89
|
+
* - `accessToken`: The original token string.
|
|
90
90
|
* If the issuer URL doesn't match the expected format, the function returns the full decoded token details.
|
|
91
91
|
*
|
|
92
92
|
* @throws Will throw an error if:
|
|
@@ -139,7 +139,7 @@ export function decodeToken(token) {
|
|
|
139
139
|
return {
|
|
140
140
|
environment: match[2],
|
|
141
141
|
tenant: match[3],
|
|
142
|
-
token,
|
|
142
|
+
accessToken: token,
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
145
|
}
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-console */\r\n/**\r\n * Returns the localized name of a language given its BCP-47 code.\r\n *\r\n * @param languageCode - The BCP-47 language code (e.g. \"en\")\r\n * @returns The localized language name (e.g. \"English\") or the original code if unavailable.\r\n */\r\nexport function getLanguageName(languageCode: string): string {\r\n const userLocale = navigator.language || 'en';\r\n const displayNames = new Intl.DisplayNames([userLocale], {\r\n type: 'language',\r\n });\r\n const languageName = displayNames.of(languageCode);\r\n return languageName || languageCode;\r\n}\r\n\r\n/**\r\n * Requests access to the microphone.\r\n *\r\n * This function checks if the microphone permission is in \"prompt\" state, then requests\r\n * access and stops any active tracks immediately. It also logs if permission is already granted.\r\n *\r\n * @returns A promise that resolves when the permission request is complete.\r\n */\r\nexport async function requestMicAccess(): Promise<void> {\r\n try {\r\n // Fallback if Permissions API is not available\r\n if (!navigator.permissions) {\r\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\r\n stream.getTracks().forEach(track => track.stop());\r\n return;\r\n }\r\n\r\n const permissionStatus = await navigator.permissions.query({\r\n // eslint-disable-next-line no-undef\r\n name: 'microphone' as PermissionName,\r\n });\r\n\r\n if (permissionStatus.state === 'prompt') {\r\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\r\n stream.getTracks().forEach(track => track.stop());\r\n } else if (permissionStatus.state === 'denied') {\r\n console.warn('Microphone permission is denied.');\r\n }\r\n } catch (error) {\r\n console.error('Error checking/requesting microphone permission:', error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves available audio input devices.\r\n *\r\n * This function uses the mediaDevices API to enumerate devices and filters out those\r\n * which are audio inputs. In some browsers, you may need to request user media before\r\n * device labels are populated.\r\n *\r\n * @returns A promise that resolves with an object containing:\r\n * - `devices`: an array of MediaDeviceInfo objects for audio inputs.\r\n * - `defaultDeviceId`: the deviceId of the first audio input, if available.\r\n */\r\nexport async function getAudioDevices(): Promise<{\r\n devices: MediaDeviceInfo[];\r\n defaultDevice?: MediaDeviceInfo;\r\n}> {\r\n if (!navigator.mediaDevices?.enumerateDevices) {\r\n console.error('Media devices API not supported.');\r\n return { devices: [] };\r\n }\r\n\r\n await requestMicAccess();\r\n\r\n try {\r\n // Optionally: await navigator.mediaDevices.getUserMedia({ audio: true });\r\n const devices = await navigator.mediaDevices.enumerateDevices();\r\n const audioDevices = devices.filter(device => device.kind === 'audioinput');\r\n const defaultDevice = audioDevices.length > 0 ? audioDevices[0] : undefined;\r\n return { devices: audioDevices, defaultDevice };\r\n } catch (error) {\r\n console.error('Error enumerating devices:', error);\r\n return { devices: [] };\r\n }\r\n}\r\n\r\n/**\r\n * Decodes a JWT token and extracts environment and tenant details from its issuer URL.\r\n *\r\n * This function assumes the JWT token follows the standard header.payload.signature format.\r\n * It decodes the payload from base64 URL format, parses it as JSON, and then uses a regex\r\n * to extract the `environment` and `tenant` from the issuer URL (iss field) if it matches the pattern:\r\n * https://keycloak.{environment}.corti.app/realms/{tenant}.\r\n *\r\n * @param token - A JSON Web Token (JWT) string.\r\n * @returns An object containing:\r\n * - `environment`: The extracted environment from the issuer URL.\r\n * - `tenant`: The extracted tenant from the issuer URL.\r\n * - `token`: The original token string.\r\n * If the issuer URL doesn't match the expected format, the function returns the full decoded token details.\r\n *\r\n * @throws Will throw an error if:\r\n * - The token format is invalid.\r\n * - The base64 decoding or URI decoding fails.\r\n * - The JSON payload is invalid.\r\n * - The token payload does not contain an issuer (iss) field.\r\n */\r\nexport function decodeToken(token: string) {\r\n // Validate the token structure (should contain at least header and payload parts)\r\n const parts = token.split('.');\r\n if (parts.length < 2) {\r\n throw new Error('Invalid token format');\r\n }\r\n\r\n // Retrieve the payload (second part) of the JWT token\r\n const base64Url = parts[1];\r\n\r\n // Replace URL-safe characters to match standard base64 encoding\r\n const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');\r\n\r\n // Decode the base64 string into a JSON string\r\n let jsonPayload: string;\r\n try {\r\n jsonPayload = decodeURIComponent(\r\n atob(base64)\r\n .split('')\r\n .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\r\n .join(''),\r\n );\r\n } catch (error) {\r\n throw new Error('Failed to decode token payload');\r\n }\r\n\r\n // Parse the JSON string to obtain token details\r\n let tokenDetails: { iss: string; [key: string]: unknown };\r\n try {\r\n tokenDetails = JSON.parse(jsonPayload);\r\n } catch (error) {\r\n throw new Error('Invalid JSON payload in token');\r\n }\r\n\r\n // Extract the issuer URL from the token details\r\n const issuerUrl: string = tokenDetails.iss;\r\n if (!issuerUrl) {\r\n throw new Error('Token payload does not contain an issuer (iss) field');\r\n }\r\n\r\n // Regex to extract environment and tenant from issuer URL:\r\n // Expected format: https://keycloak.{environment}.corti.app/realms/{tenant}\r\n // Note: Unnecessary escapes in character classes have been removed.\r\n const regex =\r\n /^https:\\/\\/(keycloak|auth)\\.([^.]+)\\.corti\\.app\\/realms\\/([^/]+)/;\r\n const match = issuerUrl.match(regex);\r\n\r\n // If the issuer URL matches the expected pattern, return the extracted values along with the token\r\n if (match) {\r\n return {\r\n environment: match[2],\r\n tenant: match[3],\r\n token,\r\n };\r\n }\r\n}\r\n\r\nexport async function getMediaStream(deviceId?: string): Promise<MediaStream> {\r\n if (!deviceId) {\r\n throw new Error('No device ID provided');\r\n }\r\n\r\n if (deviceId === 'display_audio') {\r\n const stream = await navigator.mediaDevices.getDisplayMedia({\r\n audio: true,\r\n video: true,\r\n });\r\n stream.getTracks().forEach(track => {\r\n if (track.kind === 'video') {\r\n stream.removeTrack(track);\r\n }\r\n });\r\n return stream;\r\n }\r\n\r\n // Get media stream and initialize audio service.\r\n const constraints: MediaStreamConstraints =\r\n deviceId !== 'default'\r\n ? { audio: { deviceId: { exact: deviceId } } }\r\n : { audio: true };\r\n\r\n return await navigator.mediaDevices.getUserMedia(constraints);\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-console */\n/**\n * Returns the localized name of a language given its BCP-47 code.\n *\n * @param languageCode - The BCP-47 language code (e.g. \"en\")\n * @returns The localized language name (e.g. \"English\") or the original code if unavailable.\n */\nexport function getLanguageName(languageCode: string): string {\n const userLocale = navigator.language || 'en';\n const displayNames = new Intl.DisplayNames([userLocale], {\n type: 'language',\n });\n const languageName = displayNames.of(languageCode);\n return languageName || languageCode;\n}\n\n/**\n * Requests access to the microphone.\n *\n * This function checks if the microphone permission is in \"prompt\" state, then requests\n * access and stops any active tracks immediately. It also logs if permission is already granted.\n *\n * @returns A promise that resolves when the permission request is complete.\n */\nexport async function requestMicAccess(): Promise<void> {\n try {\n // Fallback if Permissions API is not available\n if (!navigator.permissions) {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach(track => track.stop());\n return;\n }\n\n const permissionStatus = await navigator.permissions.query({\n // eslint-disable-next-line no-undef\n name: 'microphone' as PermissionName,\n });\n\n if (permissionStatus.state === 'prompt') {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach(track => track.stop());\n } else if (permissionStatus.state === 'denied') {\n console.warn('Microphone permission is denied.');\n }\n } catch (error) {\n console.error('Error checking/requesting microphone permission:', error);\n }\n}\n\n/**\n * Retrieves available audio input devices.\n *\n * This function uses the mediaDevices API to enumerate devices and filters out those\n * which are audio inputs. In some browsers, you may need to request user media before\n * device labels are populated.\n *\n * @returns A promise that resolves with an object containing:\n * - `devices`: an array of MediaDeviceInfo objects for audio inputs.\n * - `defaultDeviceId`: the deviceId of the first audio input, if available.\n */\nexport async function getAudioDevices(): Promise<{\n devices: MediaDeviceInfo[];\n defaultDevice?: MediaDeviceInfo;\n}> {\n if (!navigator.mediaDevices?.enumerateDevices) {\n console.error('Media devices API not supported.');\n return { devices: [] };\n }\n\n await requestMicAccess();\n\n try {\n // Optionally: await navigator.mediaDevices.getUserMedia({ audio: true });\n const devices = await navigator.mediaDevices.enumerateDevices();\n const audioDevices = devices.filter(device => device.kind === 'audioinput');\n const defaultDevice = audioDevices.length > 0 ? audioDevices[0] : undefined;\n return { devices: audioDevices, defaultDevice };\n } catch (error) {\n console.error('Error enumerating devices:', error);\n return { devices: [] };\n }\n}\n\n/**\n * Decodes a JWT token and extracts environment and tenant details from its issuer URL.\n *\n * This function assumes the JWT token follows the standard header.payload.signature format.\n * It decodes the payload from base64 URL format, parses it as JSON, and then uses a regex\n * to extract the `environment` and `tenant` from the issuer URL (iss field) if it matches the pattern:\n * https://keycloak.{environment}.corti.app/realms/{tenant}.\n *\n * @param token - A JSON Web Token (JWT) string.\n * @returns An object containing:\n * - `environment`: The extracted environment from the issuer URL.\n * - `tenant`: The extracted tenant from the issuer URL.\n * - `accessToken`: The original token string.\n * If the issuer URL doesn't match the expected format, the function returns the full decoded token details.\n *\n * @throws Will throw an error if:\n * - The token format is invalid.\n * - The base64 decoding or URI decoding fails.\n * - The JSON payload is invalid.\n * - The token payload does not contain an issuer (iss) field.\n */\nexport function decodeToken(token: string) {\n // Validate the token structure (should contain at least header and payload parts)\n const parts = token.split('.');\n if (parts.length < 2) {\n throw new Error('Invalid token format');\n }\n\n // Retrieve the payload (second part) of the JWT token\n const base64Url = parts[1];\n\n // Replace URL-safe characters to match standard base64 encoding\n const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');\n\n // Decode the base64 string into a JSON string\n let jsonPayload: string;\n try {\n jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\n .join(''),\n );\n } catch (error) {\n throw new Error('Failed to decode token payload');\n }\n\n // Parse the JSON string to obtain token details\n let tokenDetails: { iss: string; [key: string]: unknown };\n try {\n tokenDetails = JSON.parse(jsonPayload);\n } catch (error) {\n throw new Error('Invalid JSON payload in token');\n }\n\n // Extract the issuer URL from the token details\n const issuerUrl: string = tokenDetails.iss;\n if (!issuerUrl) {\n throw new Error('Token payload does not contain an issuer (iss) field');\n }\n\n // Regex to extract environment and tenant from issuer URL:\n // Expected format: https://keycloak.{environment}.corti.app/realms/{tenant}\n // Note: Unnecessary escapes in character classes have been removed.\n const regex =\n /^https:\\/\\/(keycloak|auth)\\.([^.]+)\\.corti\\.app\\/realms\\/([^/]+)/;\n const match = issuerUrl.match(regex);\n\n // If the issuer URL matches the expected pattern, return the extracted values along with the token\n if (match) {\n return {\n environment: match[2],\n tenant: match[3],\n accessToken: token,\n };\n }\n}\n\nexport async function getMediaStream(deviceId?: string): Promise<MediaStream> {\n if (!deviceId) {\n throw new Error('No device ID provided');\n }\n\n if (deviceId === 'display_audio') {\n const stream = await navigator.mediaDevices.getDisplayMedia({\n audio: true,\n video: true,\n });\n stream.getTracks().forEach(track => {\n if (track.kind === 'video') {\n stream.removeTrack(track);\n }\n });\n return stream;\n }\n\n // Get media stream and initialize audio service.\n const constraints: MediaStreamConstraints =\n deviceId !== 'default'\n ? { audio: { deviceId: { exact: deviceId } } }\n : { audio: true };\n\n return await navigator.mediaDevices.getUserMedia(constraints);\n}\n"]}
|