@corti/dictation-web 0.1.5 → 0.1.7
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 +108 -101
- package/dist/CortiDictation.d.ts +10 -4
- package/dist/CortiDictation.js +82 -53
- package/dist/CortiDictation.js.map +1 -1
- package/dist/DictationService.d.ts +0 -1
- package/dist/DictationService.js +27 -8
- package/dist/DictationService.js.map +1 -1
- package/dist/RecorderManager.d.ts +5 -2
- package/dist/RecorderManager.js +62 -15
- package/dist/RecorderManager.js.map +1 -1
- package/dist/bundle.js +206 -69
- package/dist/components/settings-menu.d.ts +5 -2
- package/dist/components/settings-menu.js +30 -14
- 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/ComponentStyles.js +1 -0
- package/dist/styles/ComponentStyles.js.map +1 -1
- package/dist/styles/callout.js +29 -22
- package/dist/styles/callout.js.map +1 -1
- package/dist/types.d.ts +9 -3
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +25 -3
- package/dist/utils.js.map +1 -1
- package/package.json +7 -5
package/dist/RecorderManager.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { getAudioDevices } from './utils.js';
|
|
1
|
+
import { getAudioDevices, getMediaStream } from './utils.js';
|
|
2
2
|
import { AudioService } from './audioService.js';
|
|
3
3
|
import { DictationService } from './DictationService.js';
|
|
4
4
|
export class RecorderManager extends EventTarget {
|
|
5
5
|
constructor() {
|
|
6
|
-
super(
|
|
6
|
+
super();
|
|
7
7
|
this.devices = [];
|
|
8
|
-
this.selectedDevice = '';
|
|
9
8
|
this.recordingState = 'stopped';
|
|
10
9
|
this._mediaStream = null;
|
|
11
10
|
this._audioService = null;
|
|
12
11
|
this._dictationService = null;
|
|
12
|
+
navigator.mediaDevices.addEventListener('devicechange', this.handleDevicesChange.bind(this));
|
|
13
13
|
}
|
|
14
14
|
async initialize() {
|
|
15
15
|
const deviceResponse = await getAudioDevices();
|
|
16
16
|
this.devices = deviceResponse.devices;
|
|
17
|
-
this.selectedDevice = deviceResponse.
|
|
18
|
-
return
|
|
17
|
+
this.selectedDevice = deviceResponse.defaultDevice;
|
|
18
|
+
return { devices: this.devices, selectedDevice: this.selectedDevice };
|
|
19
19
|
}
|
|
20
20
|
dispatchCustomEvent(eventName, detail) {
|
|
21
21
|
this.dispatchEvent(new CustomEvent(eventName, {
|
|
@@ -24,34 +24,81 @@ export class RecorderManager extends EventTarget {
|
|
|
24
24
|
composed: true,
|
|
25
25
|
}));
|
|
26
26
|
}
|
|
27
|
+
async handleDevicesChange() {
|
|
28
|
+
const deviceResponse = await getAudioDevices();
|
|
29
|
+
this.devices = deviceResponse.devices;
|
|
30
|
+
if (!this.devices.find(device => device.deviceId === this.selectedDevice?.deviceId)) {
|
|
31
|
+
this.selectedDevice = deviceResponse.defaultDevice;
|
|
32
|
+
}
|
|
33
|
+
this.dispatchCustomEvent('recording-devices-changed', {
|
|
34
|
+
devices: deviceResponse.devices,
|
|
35
|
+
selectedDevice: this.selectedDevice || deviceResponse.defaultDevice,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
27
38
|
async startRecording(params) {
|
|
28
39
|
this._updateRecordingState('initializing');
|
|
29
|
-
// Get media stream and initialize audio service.
|
|
30
40
|
try {
|
|
31
|
-
this._mediaStream = await
|
|
32
|
-
|
|
41
|
+
this._mediaStream = await getMediaStream(params.debug_displayAudio
|
|
42
|
+
? 'display_audio'
|
|
43
|
+
: this.selectedDevice?.deviceId);
|
|
44
|
+
this._mediaStream.getTracks().forEach((track) => {
|
|
45
|
+
track.addEventListener('ended', () => {
|
|
46
|
+
if (this.recordingState === 'recording') {
|
|
47
|
+
this.dispatchCustomEvent('error', {
|
|
48
|
+
message: 'Microphone access was lost.',
|
|
49
|
+
});
|
|
50
|
+
this.stopRecording();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
33
53
|
});
|
|
34
54
|
this._audioService = new AudioService(this._mediaStream);
|
|
35
55
|
}
|
|
36
56
|
catch (error) {
|
|
37
57
|
this.dispatchCustomEvent('error', error);
|
|
38
|
-
this.
|
|
58
|
+
this.stopRecording();
|
|
39
59
|
return;
|
|
40
60
|
}
|
|
41
61
|
// Initialize dictation service.
|
|
42
62
|
try {
|
|
43
63
|
this._dictationService = new DictationService(this._mediaStream, params);
|
|
64
|
+
// Forward custom events from dictation service
|
|
65
|
+
this._dictationService.addEventListener('error', e => {
|
|
66
|
+
this.dispatchEvent(new CustomEvent('error', {
|
|
67
|
+
detail: e.detail,
|
|
68
|
+
bubbles: true,
|
|
69
|
+
composed: true,
|
|
70
|
+
}));
|
|
71
|
+
this.stopRecording();
|
|
72
|
+
});
|
|
73
|
+
this._dictationService.addEventListener('stream-closed', () => this.stopRecording());
|
|
74
|
+
this._dictationService.addEventListener('transcript', e => this.dispatchEvent(new CustomEvent('transcript', {
|
|
75
|
+
detail: e.detail,
|
|
76
|
+
bubbles: true,
|
|
77
|
+
composed: true,
|
|
78
|
+
})));
|
|
79
|
+
this._dictationService.addEventListener('command', e => this.dispatchEvent(new CustomEvent('command', {
|
|
80
|
+
detail: e.detail,
|
|
81
|
+
bubbles: true,
|
|
82
|
+
composed: true,
|
|
83
|
+
})));
|
|
44
84
|
}
|
|
45
85
|
catch (error) {
|
|
46
86
|
this.dispatchCustomEvent('error', error);
|
|
47
87
|
this.stopRecording();
|
|
48
88
|
return;
|
|
49
89
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
90
|
+
try {
|
|
91
|
+
this._dictationService?.startRecording();
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
this.dispatchEvent(new CustomEvent('error', {
|
|
95
|
+
detail: error,
|
|
96
|
+
bubbles: true,
|
|
97
|
+
composed: true,
|
|
98
|
+
}));
|
|
99
|
+
this.stopRecording();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
55
102
|
this._updateRecordingState('recording');
|
|
56
103
|
// Update audio level visualization.
|
|
57
104
|
this._visualiserInterval = window.setInterval(() => {
|
|
@@ -69,8 +116,8 @@ export class RecorderManager extends EventTarget {
|
|
|
69
116
|
}
|
|
70
117
|
if (this._mediaStream) {
|
|
71
118
|
this._mediaStream.getTracks().forEach(track => track.stop());
|
|
72
|
-
this._mediaStream = null;
|
|
73
119
|
}
|
|
120
|
+
this.dispatchCustomEvent('audio-level-changed', { audioLevel: 0 });
|
|
74
121
|
await this._dictationService?.stopRecording();
|
|
75
122
|
this._updateRecordingState('stopped');
|
|
76
123
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecorderManager.js","sourceRoot":"","sources":["../src/RecorderManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { getAudioDevices } from './utils.js';\nimport { AudioService } from './audioService.js';\nimport { DictationService } from './DictationService.js';\nimport type { DictationConfig, RecordingState } from './types.js';\n\nexport class RecorderManager extends EventTarget {\n public devices: MediaDeviceInfo[] = [];\n\n public selectedDevice: string = '';\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 async initialize() {\n const deviceResponse = await getAudioDevices();\n this.devices = deviceResponse.devices;\n this.selectedDevice = deviceResponse.defaultDeviceId || '';\n return deviceResponse;\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 async startRecording(params: {\n dictationConfig: DictationConfig;\n authToken: string;\n }): Promise<void> {\n this._updateRecordingState('initializing');\n\n // Get media stream and initialize audio service.\n try {\n this._mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: { deviceId: this.selectedDevice },\n });\n this._audioService = new AudioService(this._mediaStream);\n } catch (error) {\n this.dispatchCustomEvent('error', error);\n this._updateRecordingState('stopped');\n return;\n }\n\n // Initialize dictation service.\n try {\n this._dictationService = new DictationService(this._mediaStream, params);\n } catch (error) {\n this.dispatchCustomEvent('error', error);\n this.stopRecording();\n return;\n }\n\n // Forward dictation service events.\n this._dictationService.addEventListener('error', e =>\n this.dispatchCustomEvent('error', (e as CustomEvent).detail),\n );\n this._dictationService.addEventListener('stream-closed', () =>\n this.stopRecording(),\n );\n this._dictationService.addEventListener('transcript', e =>\n this.dispatchCustomEvent('transcript', (e as CustomEvent).detail),\n );\n\n this._dictationService.startRecording();\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 this._mediaStream = null;\n }\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"]}
|
|
1
|
+
{"version":3,"file":"RecorderManager.js","sourceRoot":"","sources":["../src/RecorderManager.ts"],"names":[],"mappings":"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","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"]}
|
package/dist/bundle.js
CHANGED
|
@@ -623,8 +623,8 @@ async function getAudioDevices() {
|
|
|
623
623
|
try {
|
|
624
624
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
625
625
|
const audioDevices = devices.filter((device) => device.kind === "audioinput");
|
|
626
|
-
const
|
|
627
|
-
return { devices: audioDevices,
|
|
626
|
+
const defaultDevice = audioDevices.length > 0 ? audioDevices[0] : void 0;
|
|
627
|
+
return { devices: audioDevices, defaultDevice };
|
|
628
628
|
} catch (error) {
|
|
629
629
|
console.error("Error enumerating devices:", error);
|
|
630
630
|
return { devices: [] };
|
|
@@ -633,7 +633,7 @@ async function getAudioDevices() {
|
|
|
633
633
|
function decodeToken(token) {
|
|
634
634
|
const parts = token.split(".");
|
|
635
635
|
if (parts.length < 2) {
|
|
636
|
-
throw new Error("Invalid token format
|
|
636
|
+
throw new Error("Invalid token format");
|
|
637
637
|
}
|
|
638
638
|
const base64Url = parts[1];
|
|
639
639
|
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -663,6 +663,25 @@ function decodeToken(token) {
|
|
|
663
663
|
};
|
|
664
664
|
}
|
|
665
665
|
}
|
|
666
|
+
async function getMediaStream(deviceId) {
|
|
667
|
+
if (!deviceId) {
|
|
668
|
+
throw new Error("No device ID provided");
|
|
669
|
+
}
|
|
670
|
+
if (deviceId === "display_audio") {
|
|
671
|
+
const stream = await navigator.mediaDevices.getDisplayMedia({
|
|
672
|
+
audio: true,
|
|
673
|
+
video: true
|
|
674
|
+
});
|
|
675
|
+
stream.getTracks().forEach((track) => {
|
|
676
|
+
if (track.kind === "video") {
|
|
677
|
+
stream.removeTrack(track);
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
return stream;
|
|
681
|
+
}
|
|
682
|
+
const constraints = deviceId !== "default" ? { audio: { deviceId: { exact: deviceId } } } : { audio: true };
|
|
683
|
+
return await navigator.mediaDevices.getUserMedia(constraints);
|
|
684
|
+
}
|
|
666
685
|
|
|
667
686
|
// dist/audioService.js
|
|
668
687
|
var AudioService = class {
|
|
@@ -697,7 +716,6 @@ var DictationService = class extends EventTarget {
|
|
|
697
716
|
if (!config) {
|
|
698
717
|
throw new Error("Invalid token");
|
|
699
718
|
}
|
|
700
|
-
this.serverConfig = config;
|
|
701
719
|
this.mediaRecorder.ondataavailable = (event) => {
|
|
702
720
|
if (this.webSocket?.readyState === WebSocket.OPEN) {
|
|
703
721
|
this.webSocket.send(event.data);
|
|
@@ -712,7 +730,16 @@ var DictationService = class extends EventTarget {
|
|
|
712
730
|
}));
|
|
713
731
|
}
|
|
714
732
|
startRecording() {
|
|
715
|
-
const
|
|
733
|
+
const serverConfig = decodeToken(this.authToken);
|
|
734
|
+
if (!serverConfig) {
|
|
735
|
+
this.dispatchEvent(new CustomEvent("error", {
|
|
736
|
+
detail: "Invalid token",
|
|
737
|
+
bubbles: true,
|
|
738
|
+
composed: true
|
|
739
|
+
}));
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
const url = `wss://api.${serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${serverConfig.tenant}&token=Bearer%20${this.authToken}`;
|
|
716
743
|
this.webSocket = new WebSocket(url);
|
|
717
744
|
this.webSocket.onopen = () => {
|
|
718
745
|
this.webSocket.send(JSON.stringify({
|
|
@@ -722,10 +749,22 @@ var DictationService = class extends EventTarget {
|
|
|
722
749
|
};
|
|
723
750
|
this.webSocket.onmessage = (event) => {
|
|
724
751
|
const message = JSON.parse(event.data);
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
752
|
+
switch (message.type) {
|
|
753
|
+
case "CONFIG_ACCEPTED":
|
|
754
|
+
this.mediaRecorder.start(250);
|
|
755
|
+
break;
|
|
756
|
+
case "CONFIG_DENIED":
|
|
757
|
+
this.dispatchCustomEvent("error", message);
|
|
758
|
+
return this.stopRecording();
|
|
759
|
+
case "transcript":
|
|
760
|
+
this.dispatchCustomEvent("transcript", message);
|
|
761
|
+
break;
|
|
762
|
+
case "command":
|
|
763
|
+
this.dispatchCustomEvent("command", message);
|
|
764
|
+
break;
|
|
765
|
+
default:
|
|
766
|
+
console.warn(`Unhandled message type: ${message.type}`);
|
|
767
|
+
break;
|
|
729
768
|
}
|
|
730
769
|
};
|
|
731
770
|
this.webSocket.onerror = (event) => {
|
|
@@ -736,7 +775,7 @@ var DictationService = class extends EventTarget {
|
|
|
736
775
|
};
|
|
737
776
|
}
|
|
738
777
|
async stopRecording() {
|
|
739
|
-
this.mediaRecorder
|
|
778
|
+
this.mediaRecorder?.stop();
|
|
740
779
|
if (this.webSocket?.readyState === WebSocket.OPEN) {
|
|
741
780
|
this.webSocket.send(JSON.stringify({ type: "end" }));
|
|
742
781
|
}
|
|
@@ -755,19 +794,19 @@ var DictationService = class extends EventTarget {
|
|
|
755
794
|
// dist/RecorderManager.js
|
|
756
795
|
var RecorderManager = class extends EventTarget {
|
|
757
796
|
constructor() {
|
|
758
|
-
super(
|
|
797
|
+
super();
|
|
759
798
|
this.devices = [];
|
|
760
|
-
this.selectedDevice = "";
|
|
761
799
|
this.recordingState = "stopped";
|
|
762
800
|
this._mediaStream = null;
|
|
763
801
|
this._audioService = null;
|
|
764
802
|
this._dictationService = null;
|
|
803
|
+
navigator.mediaDevices.addEventListener("devicechange", this.handleDevicesChange.bind(this));
|
|
765
804
|
}
|
|
766
805
|
async initialize() {
|
|
767
806
|
const deviceResponse = await getAudioDevices();
|
|
768
807
|
this.devices = deviceResponse.devices;
|
|
769
|
-
this.selectedDevice = deviceResponse.
|
|
770
|
-
return
|
|
808
|
+
this.selectedDevice = deviceResponse.defaultDevice;
|
|
809
|
+
return { devices: this.devices, selectedDevice: this.selectedDevice };
|
|
771
810
|
}
|
|
772
811
|
dispatchCustomEvent(eventName, detail) {
|
|
773
812
|
this.dispatchEvent(new CustomEvent(eventName, {
|
|
@@ -776,29 +815,74 @@ var RecorderManager = class extends EventTarget {
|
|
|
776
815
|
composed: true
|
|
777
816
|
}));
|
|
778
817
|
}
|
|
818
|
+
async handleDevicesChange() {
|
|
819
|
+
const deviceResponse = await getAudioDevices();
|
|
820
|
+
this.devices = deviceResponse.devices;
|
|
821
|
+
if (!this.devices.find((device) => device.deviceId === this.selectedDevice?.deviceId)) {
|
|
822
|
+
this.selectedDevice = deviceResponse.defaultDevice;
|
|
823
|
+
}
|
|
824
|
+
this.dispatchCustomEvent("recording-devices-changed", {
|
|
825
|
+
devices: deviceResponse.devices,
|
|
826
|
+
selectedDevice: this.selectedDevice || deviceResponse.defaultDevice
|
|
827
|
+
});
|
|
828
|
+
}
|
|
779
829
|
async startRecording(params) {
|
|
780
830
|
this._updateRecordingState("initializing");
|
|
781
831
|
try {
|
|
782
|
-
this._mediaStream = await
|
|
783
|
-
|
|
832
|
+
this._mediaStream = await getMediaStream(params.debug_displayAudio ? "display_audio" : this.selectedDevice?.deviceId);
|
|
833
|
+
this._mediaStream.getTracks().forEach((track) => {
|
|
834
|
+
track.addEventListener("ended", () => {
|
|
835
|
+
if (this.recordingState === "recording") {
|
|
836
|
+
this.dispatchCustomEvent("error", {
|
|
837
|
+
message: "Microphone access was lost."
|
|
838
|
+
});
|
|
839
|
+
this.stopRecording();
|
|
840
|
+
}
|
|
841
|
+
});
|
|
784
842
|
});
|
|
785
843
|
this._audioService = new AudioService(this._mediaStream);
|
|
786
844
|
} catch (error) {
|
|
787
845
|
this.dispatchCustomEvent("error", error);
|
|
788
|
-
this.
|
|
846
|
+
this.stopRecording();
|
|
789
847
|
return;
|
|
790
848
|
}
|
|
791
849
|
try {
|
|
792
850
|
this._dictationService = new DictationService(this._mediaStream, params);
|
|
851
|
+
this._dictationService.addEventListener("error", (e5) => {
|
|
852
|
+
this.dispatchEvent(new CustomEvent("error", {
|
|
853
|
+
detail: e5.detail,
|
|
854
|
+
bubbles: true,
|
|
855
|
+
composed: true
|
|
856
|
+
}));
|
|
857
|
+
this.stopRecording();
|
|
858
|
+
});
|
|
859
|
+
this._dictationService.addEventListener("stream-closed", () => this.stopRecording());
|
|
860
|
+
this._dictationService.addEventListener("transcript", (e5) => this.dispatchEvent(new CustomEvent("transcript", {
|
|
861
|
+
detail: e5.detail,
|
|
862
|
+
bubbles: true,
|
|
863
|
+
composed: true
|
|
864
|
+
})));
|
|
865
|
+
this._dictationService.addEventListener("command", (e5) => this.dispatchEvent(new CustomEvent("command", {
|
|
866
|
+
detail: e5.detail,
|
|
867
|
+
bubbles: true,
|
|
868
|
+
composed: true
|
|
869
|
+
})));
|
|
793
870
|
} catch (error) {
|
|
794
871
|
this.dispatchCustomEvent("error", error);
|
|
795
872
|
this.stopRecording();
|
|
796
873
|
return;
|
|
797
874
|
}
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
875
|
+
try {
|
|
876
|
+
this._dictationService?.startRecording();
|
|
877
|
+
} catch (error) {
|
|
878
|
+
this.dispatchEvent(new CustomEvent("error", {
|
|
879
|
+
detail: error,
|
|
880
|
+
bubbles: true,
|
|
881
|
+
composed: true
|
|
882
|
+
}));
|
|
883
|
+
this.stopRecording();
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
802
886
|
this._updateRecordingState("recording");
|
|
803
887
|
this._visualiserInterval = window.setInterval(() => {
|
|
804
888
|
const level = this._audioService ? this._audioService.getAudioLevel() * 3 : 0;
|
|
@@ -813,8 +897,8 @@ var RecorderManager = class extends EventTarget {
|
|
|
813
897
|
}
|
|
814
898
|
if (this._mediaStream) {
|
|
815
899
|
this._mediaStream.getTracks().forEach((track) => track.stop());
|
|
816
|
-
this._mediaStream = null;
|
|
817
900
|
}
|
|
901
|
+
this.dispatchCustomEvent("audio-level-changed", { audioLevel: 0 });
|
|
818
902
|
await this._dictationService?.stopRecording();
|
|
819
903
|
this._updateRecordingState("stopped");
|
|
820
904
|
}
|
|
@@ -943,7 +1027,9 @@ var CalloutStyles = i`
|
|
|
943
1027
|
display: flex;
|
|
944
1028
|
font-size: 0.9rem;
|
|
945
1029
|
gap: 8px;
|
|
946
|
-
align-items:
|
|
1030
|
+
align-items: center;
|
|
1031
|
+
max-width: 100%;
|
|
1032
|
+
height: fit-content;
|
|
947
1033
|
&.red {
|
|
948
1034
|
background: var(--callout-red-background);
|
|
949
1035
|
border: 1px solid var(--callout-red-border);
|
|
@@ -954,6 +1040,11 @@ var CalloutStyles = i`
|
|
|
954
1040
|
border: 1px solid var(--callout-orange-border);
|
|
955
1041
|
color: var(--callout-orange-text);
|
|
956
1042
|
}
|
|
1043
|
+
&.small {
|
|
1044
|
+
width: 100%;
|
|
1045
|
+
padding: 6px;
|
|
1046
|
+
font-size: 0.7rem;
|
|
1047
|
+
}
|
|
957
1048
|
}
|
|
958
1049
|
`;
|
|
959
1050
|
var callout_default = CalloutStyles;
|
|
@@ -967,17 +1058,33 @@ var __decorate = function(decorators, target, key, desc) {
|
|
|
967
1058
|
};
|
|
968
1059
|
var SettingsMenu = class SettingsMenu2 extends r4 {
|
|
969
1060
|
constructor() {
|
|
970
|
-
super(
|
|
971
|
-
this.devices = [];
|
|
972
|
-
this.selectedDevice = "";
|
|
1061
|
+
super();
|
|
973
1062
|
this.selectedLanguage = "";
|
|
974
1063
|
this.settingsDisabled = false;
|
|
1064
|
+
this._devices = [];
|
|
1065
|
+
navigator.mediaDevices.addEventListener("devicechange", this.handleDevicesChange.bind(this));
|
|
1066
|
+
}
|
|
1067
|
+
// on load, get the available devices
|
|
1068
|
+
async connectedCallback() {
|
|
1069
|
+
super.connectedCallback();
|
|
1070
|
+
const deviceResponse = await getAudioDevices();
|
|
1071
|
+
this._devices = deviceResponse.devices;
|
|
1072
|
+
}
|
|
1073
|
+
async handleDevicesChange() {
|
|
1074
|
+
const deviceResponse = await getAudioDevices();
|
|
1075
|
+
this._devices = deviceResponse.devices;
|
|
975
1076
|
}
|
|
976
1077
|
_selectDevice(deviceId) {
|
|
977
|
-
this.
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1078
|
+
const device = this._devices.find((d3) => d3.deviceId === deviceId);
|
|
1079
|
+
if (!device) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
this.selectedDevice = device;
|
|
1083
|
+
this.dispatchEvent(new CustomEvent("recording-devices-changed", {
|
|
1084
|
+
detail: {
|
|
1085
|
+
devices: this._devices,
|
|
1086
|
+
selectedDevice: device
|
|
1087
|
+
},
|
|
981
1088
|
bubbles: true,
|
|
982
1089
|
composed: true
|
|
983
1090
|
}));
|
|
@@ -1007,10 +1114,10 @@ var SettingsMenu = class SettingsMenu2 extends r4 {
|
|
|
1007
1114
|
}}
|
|
1008
1115
|
?disabled=${this.settingsDisabled}
|
|
1009
1116
|
>
|
|
1010
|
-
${this.
|
|
1117
|
+
${this._devices.map((device) => x`
|
|
1011
1118
|
<option
|
|
1012
1119
|
value=${device.deviceId}
|
|
1013
|
-
?selected=${this.selectedDevice === device
|
|
1120
|
+
?selected=${this.selectedDevice === device}
|
|
1014
1121
|
>
|
|
1015
1122
|
${device.label || "Unknown Device"}
|
|
1016
1123
|
</option>
|
|
@@ -1084,9 +1191,6 @@ SettingsMenu.styles = [
|
|
|
1084
1191
|
select_default,
|
|
1085
1192
|
callout_default
|
|
1086
1193
|
];
|
|
1087
|
-
__decorate([
|
|
1088
|
-
n4({ type: Array })
|
|
1089
|
-
], SettingsMenu.prototype, "devices", void 0);
|
|
1090
1194
|
__decorate([
|
|
1091
1195
|
n4({ type: String })
|
|
1092
1196
|
], SettingsMenu.prototype, "selectedDevice", void 0);
|
|
@@ -1096,6 +1200,9 @@ __decorate([
|
|
|
1096
1200
|
__decorate([
|
|
1097
1201
|
n4({ type: Boolean })
|
|
1098
1202
|
], SettingsMenu.prototype, "settingsDisabled", void 0);
|
|
1203
|
+
__decorate([
|
|
1204
|
+
r6()
|
|
1205
|
+
], SettingsMenu.prototype, "_devices", void 0);
|
|
1099
1206
|
SettingsMenu = __decorate([
|
|
1100
1207
|
t3("settings-menu")
|
|
1101
1208
|
], SettingsMenu);
|
|
@@ -1399,6 +1506,7 @@ var ComponentStyles = i`
|
|
|
1399
1506
|
width: min-content;
|
|
1400
1507
|
gap: 4px;
|
|
1401
1508
|
height: 46px;
|
|
1509
|
+
width: 98px;
|
|
1402
1510
|
box-sizing: border-box;
|
|
1403
1511
|
overflow: hidden;
|
|
1404
1512
|
}
|
|
@@ -1449,19 +1557,28 @@ var __decorate4 = function(decorators, target, key, desc) {
|
|
|
1449
1557
|
var CortiDictation = class extends r4 {
|
|
1450
1558
|
constructor() {
|
|
1451
1559
|
super(...arguments);
|
|
1452
|
-
this.devices = [];
|
|
1453
|
-
this.recordingState = "stopped";
|
|
1454
1560
|
this.dictationConfig = DEFAULT_DICTATION_CONFIG;
|
|
1561
|
+
this.debug_displayAudio = false;
|
|
1455
1562
|
this._audioLevel = 0;
|
|
1563
|
+
this._recordingState = "stopped";
|
|
1564
|
+
this._devices = [];
|
|
1456
1565
|
this.recorderManager = new RecorderManager();
|
|
1457
1566
|
}
|
|
1458
1567
|
async connectedCallback() {
|
|
1459
1568
|
super.connectedCallback();
|
|
1460
|
-
await this.recorderManager.initialize();
|
|
1461
|
-
|
|
1569
|
+
const devices = await this.recorderManager.initialize();
|
|
1570
|
+
if (devices.selectedDevice) {
|
|
1571
|
+
this._selectedDevice = this.recorderManager.selectedDevice;
|
|
1572
|
+
this._devices = this.recorderManager.devices;
|
|
1573
|
+
this.dispatchEvent(new CustomEvent("ready"));
|
|
1574
|
+
}
|
|
1462
1575
|
const eventHandlers = {
|
|
1463
1576
|
"recording-state-changed": (e5) => {
|
|
1464
|
-
this.
|
|
1577
|
+
this._recordingState = e5.detail.state;
|
|
1578
|
+
},
|
|
1579
|
+
"devices-changed": () => {
|
|
1580
|
+
this._devices = [...this.recorderManager.devices];
|
|
1581
|
+
this.requestUpdate();
|
|
1465
1582
|
},
|
|
1466
1583
|
"audio-level-changed": (e5) => {
|
|
1467
1584
|
this._audioLevel = e5.detail.audioLevel;
|
|
@@ -1470,9 +1587,12 @@ var CortiDictation = class extends r4 {
|
|
|
1470
1587
|
};
|
|
1471
1588
|
const eventsToRelay = [
|
|
1472
1589
|
"recording-state-changed",
|
|
1590
|
+
"recording-devices-changed",
|
|
1473
1591
|
"audio-level-changed",
|
|
1474
1592
|
"error",
|
|
1475
|
-
"transcript"
|
|
1593
|
+
"transcript",
|
|
1594
|
+
"command",
|
|
1595
|
+
"ready"
|
|
1476
1596
|
];
|
|
1477
1597
|
eventsToRelay.forEach((eventName) => {
|
|
1478
1598
|
this.recorderManager.addEventListener(eventName, (e5) => {
|
|
@@ -1491,45 +1611,57 @@ var CortiDictation = class extends r4 {
|
|
|
1491
1611
|
toggleRecording() {
|
|
1492
1612
|
this._toggleRecording();
|
|
1493
1613
|
}
|
|
1494
|
-
|
|
1614
|
+
get selectedDevice() {
|
|
1615
|
+
return this.recorderManager.selectedDevice || null;
|
|
1616
|
+
}
|
|
1617
|
+
get recordingState() {
|
|
1618
|
+
return this._recordingState;
|
|
1619
|
+
}
|
|
1620
|
+
get devices() {
|
|
1621
|
+
return this._devices;
|
|
1622
|
+
}
|
|
1623
|
+
async setRecordingDevice(device) {
|
|
1624
|
+
this.recorderManager.selectedDevice = device;
|
|
1625
|
+
this._selectedDevice = device;
|
|
1495
1626
|
if (!this.authToken)
|
|
1496
1627
|
return;
|
|
1497
|
-
if (this.
|
|
1498
|
-
this.recorderManager.stopRecording();
|
|
1499
|
-
|
|
1500
|
-
this.recorderManager.startRecording({
|
|
1628
|
+
if (this._recordingState === "recording") {
|
|
1629
|
+
await this.recorderManager.stopRecording();
|
|
1630
|
+
await this.recorderManager.startRecording({
|
|
1501
1631
|
dictationConfig: this.dictationConfig,
|
|
1502
1632
|
authToken: this.authToken
|
|
1503
1633
|
});
|
|
1504
1634
|
}
|
|
1505
1635
|
}
|
|
1506
|
-
|
|
1507
|
-
async _onRecordingDeviceChanged(event) {
|
|
1508
|
-
const customEvent = event;
|
|
1636
|
+
_toggleRecording() {
|
|
1509
1637
|
if (!this.authToken)
|
|
1510
1638
|
return;
|
|
1511
|
-
this.
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1639
|
+
if (this._recordingState === "recording") {
|
|
1640
|
+
this.recorderManager.stopRecording();
|
|
1641
|
+
} else if (this._recordingState === "stopped") {
|
|
1642
|
+
this.recorderManager.startRecording({
|
|
1515
1643
|
dictationConfig: this.dictationConfig,
|
|
1516
|
-
authToken: this.authToken
|
|
1644
|
+
authToken: this.authToken,
|
|
1645
|
+
debug_displayAudio: this.debug_displayAudio
|
|
1517
1646
|
});
|
|
1518
1647
|
}
|
|
1519
1648
|
}
|
|
1649
|
+
// Handle device change events if needed
|
|
1650
|
+
async _onRecordingDevicesChanged(event) {
|
|
1651
|
+
const customEvent = event;
|
|
1652
|
+
this.setRecordingDevice(customEvent.detail.selectedDevice);
|
|
1653
|
+
}
|
|
1520
1654
|
render() {
|
|
1521
1655
|
const isConfigured = this.authToken;
|
|
1522
1656
|
if (!isConfigured) {
|
|
1523
1657
|
return x`
|
|
1524
1658
|
<div class="wrapper">
|
|
1525
|
-
<div class="callout red
|
|
1526
|
-
Please configure the server settings in the parent component.
|
|
1527
|
-
</div>
|
|
1659
|
+
<div class="callout red small">No Auth Token</div>
|
|
1528
1660
|
</div>
|
|
1529
1661
|
`;
|
|
1530
1662
|
}
|
|
1531
|
-
const isLoading = this.
|
|
1532
|
-
const isRecording = this.
|
|
1663
|
+
const isLoading = this._recordingState === "initializing" || this._recordingState === "stopping";
|
|
1664
|
+
const isRecording = this._recordingState === "recording";
|
|
1533
1665
|
return x`
|
|
1534
1666
|
<div class="wrapper">
|
|
1535
1667
|
<button
|
|
@@ -1544,31 +1676,36 @@ var CortiDictation = class extends r4 {
|
|
|
1544
1676
|
</button>
|
|
1545
1677
|
|
|
1546
1678
|
<settings-menu
|
|
1547
|
-
.
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
@recording-device-changed=${this._onRecordingDeviceChanged}
|
|
1679
|
+
.selectedDevice=${this._selectedDevice}
|
|
1680
|
+
?settingsDisabled=${this._recordingState !== "stopped"}
|
|
1681
|
+
@recording-devices-changed=${this._onRecordingDevicesChanged}
|
|
1551
1682
|
></settings-menu>
|
|
1552
1683
|
</div>
|
|
1553
1684
|
`;
|
|
1554
1685
|
}
|
|
1555
1686
|
};
|
|
1556
1687
|
CortiDictation.styles = [buttons_default, theme_default, ComponentStyles_default, callout_default];
|
|
1557
|
-
__decorate4([
|
|
1558
|
-
n4({ type: Array })
|
|
1559
|
-
], CortiDictation.prototype, "devices", void 0);
|
|
1560
|
-
__decorate4([
|
|
1561
|
-
n4({ type: String, reflect: true })
|
|
1562
|
-
], CortiDictation.prototype, "recordingState", void 0);
|
|
1563
1688
|
__decorate4([
|
|
1564
1689
|
n4({ type: Object })
|
|
1565
1690
|
], CortiDictation.prototype, "dictationConfig", void 0);
|
|
1566
1691
|
__decorate4([
|
|
1567
1692
|
n4({ type: String })
|
|
1568
1693
|
], CortiDictation.prototype, "authToken", void 0);
|
|
1694
|
+
__decorate4([
|
|
1695
|
+
n4({ type: Boolean })
|
|
1696
|
+
], CortiDictation.prototype, "debug_displayAudio", void 0);
|
|
1569
1697
|
__decorate4([
|
|
1570
1698
|
r6()
|
|
1571
1699
|
], CortiDictation.prototype, "_audioLevel", void 0);
|
|
1700
|
+
__decorate4([
|
|
1701
|
+
r6()
|
|
1702
|
+
], CortiDictation.prototype, "_recordingState", void 0);
|
|
1703
|
+
__decorate4([
|
|
1704
|
+
r6()
|
|
1705
|
+
], CortiDictation.prototype, "_selectedDevice", void 0);
|
|
1706
|
+
__decorate4([
|
|
1707
|
+
r6()
|
|
1708
|
+
], CortiDictation.prototype, "_devices", void 0);
|
|
1572
1709
|
var CortiDictation_default = CortiDictation;
|
|
1573
1710
|
|
|
1574
1711
|
// dist/index.js
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { LitElement, TemplateResult, CSSResultGroup } from 'lit';
|
|
2
2
|
export declare class SettingsMenu extends LitElement {
|
|
3
|
-
|
|
4
|
-
selectedDevice: string;
|
|
3
|
+
selectedDevice: MediaDeviceInfo | undefined;
|
|
5
4
|
selectedLanguage: string;
|
|
6
5
|
settingsDisabled: boolean;
|
|
6
|
+
private _devices;
|
|
7
|
+
constructor();
|
|
8
|
+
connectedCallback(): Promise<void>;
|
|
9
|
+
private handleDevicesChange;
|
|
7
10
|
static styles: CSSResultGroup;
|
|
8
11
|
private _selectDevice;
|
|
9
12
|
render(): TemplateResult;
|