@corti/dictation-web 0.0.1 → 0.0.2
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/dist/{src/index.js → CortiDictation.js} +1 -1
- package/dist/CortiDictation.js.map +1 -0
- package/dist/{src/DictationService.js → DictationService.js} +1 -1
- package/dist/DictationService.js.map +1 -0
- package/dist/RecorderManager.js.map +1 -0
- package/dist/audioService.js.map +1 -0
- package/dist/components/audio-visualiser.js.map +1 -0
- package/dist/components/settings-menu.js.map +1 -0
- package/dist/constants.js.map +1 -0
- package/dist/icons/icons.js.map +1 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/styles/ComponentStyles.js.map +1 -0
- package/dist/styles/buttons.js.map +1 -0
- package/dist/styles/callout.js.map +1 -0
- package/dist/styles/select.js.map +1 -0
- package/dist/styles/theme.js.map +1 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.js.map +1 -0
- package/package.json +6 -6
- package/.editorconfig +0 -29
- package/.eslintrc.json +0 -16
- package/.husky/pre-commit +0 -1
- package/.storybook/main.js +0 -8
- package/demo/index.html +0 -98
- package/dist/src/CortiDictation.d.ts +0 -19
- package/dist/src/CortiDictation.js +0 -137
- package/dist/src/CortiDictation.js.map +0 -1
- package/dist/src/DictationService.js.map +0 -1
- package/dist/src/RecorderManager.js.map +0 -1
- package/dist/src/audioRecorderManager.d.ts +0 -17
- package/dist/src/audioRecorderManager.js +0 -78
- package/dist/src/audioRecorderManager.js.map +0 -1
- package/dist/src/audioService.js.map +0 -1
- package/dist/src/componentStyles.d.ts +0 -1
- package/dist/src/componentStyles.js +0 -51
- package/dist/src/componentStyles.js.map +0 -1
- package/dist/src/components/audio-visualiser.js.map +0 -1
- package/dist/src/components/settings-menu.js.map +0 -1
- package/dist/src/components/visualiser.d.ts +0 -7
- package/dist/src/components/visualiser.js +0 -62
- package/dist/src/components/visualiser.js.map +0 -1
- package/dist/src/constants.js.map +0 -1
- package/dist/src/corti-dictation.d.ts +0 -1
- package/dist/src/corti-dictation.js +0 -3
- package/dist/src/corti-dictation.js.map +0 -1
- package/dist/src/dictationService.d.ts +0 -13
- package/dist/src/dictationService.js +0 -70
- package/dist/src/dictationService.js.map +0 -1
- package/dist/src/icons/icons.js.map +0 -1
- package/dist/src/icons/index.js.map +0 -1
- package/dist/src/icons/micOn.d.ts +0 -7
- package/dist/src/icons/micOn.js +0 -25
- package/dist/src/icons/micOn.js.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/mediaRecorderService.d.ts +0 -6
- package/dist/src/mediaRecorderService.js +0 -31
- package/dist/src/mediaRecorderService.js.map +0 -1
- package/dist/src/mic-selector.d.ts +0 -18
- package/dist/src/mic-selector.js +0 -131
- package/dist/src/mic-selector.js.map +0 -1
- package/dist/src/settings-menu.d.ts +0 -18
- package/dist/src/settings-menu.js +0 -131
- package/dist/src/settings-menu.js.map +0 -1
- package/dist/src/settings-popover.d.ts +0 -18
- package/dist/src/settings-popover.js +0 -131
- package/dist/src/settings-popover.js.map +0 -1
- package/dist/src/settings.d.ts +0 -18
- package/dist/src/settings.js +0 -131
- package/dist/src/settings.js.map +0 -1
- package/dist/src/styles/ComponentStyles.js.map +0 -1
- package/dist/src/styles/buttons.js.map +0 -1
- package/dist/src/styles/callout.js.map +0 -1
- package/dist/src/styles/select.js.map +0 -1
- package/dist/src/styles/theme.js.map +0 -1
- package/dist/src/types.js.map +0 -1
- package/dist/src/utils.js.map +0 -1
- package/dist/stories/index.stories.d.ts +0 -33
- package/dist/stories/index.stories.js +0 -37
- package/dist/stories/index.stories.js.map +0 -1
- package/dist/test/corti-dictation.test.d.ts +0 -1
- package/dist/test/corti-dictation.test.js +0 -100
- package/dist/test/corti-dictation.test.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/docs/DEV_README.md +0 -80
- package/src/DictationService.ts +0 -99
- package/src/RecorderManager.ts +0 -114
- package/src/audioService.ts +0 -25
- package/src/components/audio-visualiser.ts +0 -56
- package/src/components/settings-menu.ts +0 -152
- package/src/constants.ts +0 -10
- package/src/corti-dictation.ts +0 -3
- package/src/icons/icons.ts +0 -141
- package/src/icons/index.ts +0 -0
- package/src/index.ts +0 -154
- package/src/styles/ComponentStyles.ts +0 -53
- package/src/styles/buttons.ts +0 -59
- package/src/styles/callout.ts +0 -27
- package/src/styles/select.ts +0 -37
- package/src/styles/theme.ts +0 -75
- package/src/types.ts +0 -28
- package/src/utils.ts +0 -83
- package/stories/index.stories.ts +0 -60
- package/test/corti-dictation.test.ts +0 -124
- package/tsconfig.json +0 -22
- package/web-dev-server.config.js +0 -27
- package/web-test-runner.config.js +0 -41
- /package/dist/{src/index.d.ts → CortiDictation.d.ts} +0 -0
- /package/dist/{src/DictationService.d.ts → DictationService.d.ts} +0 -0
- /package/dist/{src/RecorderManager.d.ts → RecorderManager.d.ts} +0 -0
- /package/dist/{src/RecorderManager.js → RecorderManager.js} +0 -0
- /package/dist/{src/audioService.d.ts → audioService.d.ts} +0 -0
- /package/dist/{src/audioService.js → audioService.js} +0 -0
- /package/dist/{src/components → components}/audio-visualiser.d.ts +0 -0
- /package/dist/{src/components → components}/audio-visualiser.js +0 -0
- /package/dist/{src/components → components}/settings-menu.d.ts +0 -0
- /package/dist/{src/components → components}/settings-menu.js +0 -0
- /package/dist/{src/constants.d.ts → constants.d.ts} +0 -0
- /package/dist/{src/constants.js → constants.js} +0 -0
- /package/dist/{src/icons → icons}/icons.d.ts +0 -0
- /package/dist/{src/icons → icons}/icons.js +0 -0
- /package/dist/{src/icons → icons}/index.d.ts +0 -0
- /package/dist/{src/icons → icons}/index.js +0 -0
- /package/dist/{src/styles → styles}/ComponentStyles.d.ts +0 -0
- /package/dist/{src/styles → styles}/ComponentStyles.js +0 -0
- /package/dist/{src/styles → styles}/buttons.d.ts +0 -0
- /package/dist/{src/styles → styles}/buttons.js +0 -0
- /package/dist/{src/styles → styles}/callout.d.ts +0 -0
- /package/dist/{src/styles → styles}/callout.js +0 -0
- /package/dist/{src/styles → styles}/select.d.ts +0 -0
- /package/dist/{src/styles → styles}/select.js +0 -0
- /package/dist/{src/styles → styles}/theme.d.ts +0 -0
- /package/dist/{src/styles → styles}/theme.js +0 -0
- /package/dist/{src/types.d.ts → types.d.ts} +0 -0
- /package/dist/{src/types.js → types.js} +0 -0
- /package/dist/{src/utils.d.ts → utils.d.ts} +0 -0
- /package/dist/{src/utils.js → utils.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
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';\nimport './components/settings-menu';\nimport './components/audio-visualiser';\nimport './icons/icons';\nimport ThemeStyles from './styles/theme';\nimport ButtonStyles from './styles/buttons';\nimport ComponentStyles from './styles/ComponentStyles';\n\nimport { DictationConfig, ServerConfig } from './types';\nimport { DEFAULT_DICTATION_CONFIG } from './constants';\nimport CalloutStyles from './styles/callout';\n\nexport class CortiDictation extends LitElement {\n static styles = [ButtonStyles, ThemeStyles, ComponentStyles, CalloutStyles];\n\n @property({ type: Array })\n devices: MediaDeviceInfo[] = [];\n\n @property({ type: String, reflect: true })\n recordingState = 'stopped';\n\n @property({ type: Object })\n dictationConfig: DictationConfig = DEFAULT_DICTATION_CONFIG;\n\n @property({ type: Object })\n serverConfig: ServerConfig = {};\n\n @state()\n private _audioLevel = 0;\n\n private recorderManager = new RecorderManager();\n\n async connectedCallback() {\n super.connectedCallback();\n await this.recorderManager.initialize();\n this.devices = this.recorderManager.devices;\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 'audio-level-changed': e => {\n this._audioLevel = e.detail.audioLevel;\n this.requestUpdate();\n },\n };\n\n const eventsToRelay = [\n 'recording-state-changed',\n 'audio-level-changed',\n 'error',\n 'transcript',\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 _toggleRecording() {\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 });\n }\n }\n\n // Handle device change events if needed\n async _onRecordingDeviceChanged(event: Event) {\n const customEvent = event as CustomEvent;\n this.recorderManager.selectedDevice = customEvent.detail.deviceId;\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 render() {\n const isConfigured =\n this.serverConfig &&\n this.serverConfig.token &&\n this.serverConfig.environment &&\n this.serverConfig.tenant;\n if (!isConfigured) {\n return html`\n <div class=\"wrapper\">\n <div class=\"callout red tiny\">\n Please configure the server settings in the parent component.\n </div>\n </div>\n `;\n }\n\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 .devices=${this.devices}\n .selectedDevice=${this.recorderManager.selectedDevice}\n ?settingsDisabled=${this.recordingState !== 'stopped'}\n @recording-device-changed=${this._onRecordingDeviceChanged}\n ></settings-menu>\n </div>\n `;\n }\n}\n\nexport default CortiDictation;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DictationService.js","sourceRoot":"","sources":["../src/DictationService.ts"],"names":[],"mappings":"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","sourcesContent":["import { DictationConfig, ServerConfig } from './types';\n\nexport class DictationService extends EventTarget {\n private mediaRecorder: MediaRecorder;\n\n private webSocket!: WebSocket;\n\n private serverConfig!: ServerConfig;\n\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 this.mediaRecorder.ondataavailable = event => {\n // if webSocket is open, send the data\n if (this.webSocket?.readyState === WebSocket.OPEN) {\n this.webSocket.send(event.data);\n }\n };\n }\n\n public startRecording() {\n const url = `wss://api.${this.serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${this.serverConfig.tenant}&token=Bearer%20${this.serverConfig.token}`;\n this.webSocket = new WebSocket(url);\n this.webSocket.onopen = () => {\n this.webSocket.send(\n JSON.stringify({\n type: 'config',\n configuration: this.dictationConfig,\n }),\n );\n };\n this.webSocket.onmessage = event => {\n const message = JSON.parse(event.data);\n if (message.type === 'config') {\n this.mediaRecorder.start(250);\n } else if (message.type === 'transcript') {\n this.dispatchEvent(\n new CustomEvent('transcript', {\n detail: message,\n bubbles: true,\n composed: true,\n }),\n );\n }\n };\n this.webSocket.onerror = event => {\n this.dispatchEvent(\n new CustomEvent('error', {\n detail: event,\n bubbles: true,\n composed: true,\n }),\n );\n };\n this.webSocket.onclose = event => {\n this.dispatchEvent(\n new CustomEvent('stream-closed', {\n detail: event,\n bubbles: true,\n composed: true,\n }),\n );\n };\n }\n\n public async stopRecording() {\n this.mediaRecorder.stop();\n\n if (this.webSocket?.readyState === WebSocket.OPEN) {\n this.webSocket.send(\n JSON.stringify({\n type: 'end',\n }),\n );\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 implementation should be replaced by handling a proper 'ended' message from the server\n this.webSocket.onclose = () => {\n this.webSocket?.close();\n clearTimeout(timeOut);\n };\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecorderManager.js","sourceRoot":"","sources":["../src/RecorderManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,MAAM,OAAO,eAAgB,SAAQ,WAAW;IAAhD;;QACS,YAAO,GAAsB,EAAE,CAAC;QAEhC,mBAAc,GAAW,EAAE,CAAC;QAE5B,mBAAc,GAAmB,SAAS,CAAC;QAE1C,iBAAY,GAAuB,IAAI,CAAC;QAExC,kBAAa,GAAwB,IAAI,CAAC;QAE1C,sBAAiB,GAA4B,IAAI,CAAC;IAiG5D,CAAC;IA7FC,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,eAAe,IAAI,EAAE,CAAC;QAC3D,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,MAGpB;QACC,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,IAAI,CAAC,YAAY,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;gBAC5D,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE;aACzC,CAAC,CAAC;YACH,IAAI,CAAC,aAAa,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACzD,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,CACnD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,OAAO,EAAE;gBACvB,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,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;QACJ,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,qBAAqB,CAAC,SAAS,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QAED,IAAI,CAAC,iBAAiB,EAAE,cAAc,EAAE,CAAC;QACzC,IAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;QACxC,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,aAAa,CAChB,IAAI,WAAW,CAAC,qBAAqB,EAAE;gBACrC,MAAM,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE;gBAC7B,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;aACf,CAAC,CACH,CAAC;QACJ,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;YAC7D,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,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 } from './utils';\nimport { AudioService } from './audioService';\nimport { DictationService } from './DictationService';\nimport type { DictationConfig, RecordingState, ServerConfig } from './types';\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\n async startRecording(params: {\n dictationConfig: DictationConfig;\n serverConfig: ServerConfig;\n }) {\n this._updateRecordingState('initializing');\n try {\n this._mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: { deviceId: this.selectedDevice },\n });\n this._audioService = new AudioService(this._mediaStream);\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 );\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 } catch (error) {\n this.dispatchEvent(\n new CustomEvent('error', {\n detail: error,\n bubbles: true,\n composed: true,\n }),\n );\n this._updateRecordingState('stopped');\n return;\n }\n\n this._dictationService?.startRecording();\n this._updateRecordingState('recording');\n this._visualiserInterval = window.setInterval(() => {\n const level = this._audioService\n ? this._audioService.getAudioLevel() * 3\n : 0;\n this.dispatchEvent(\n new CustomEvent('audio-level-changed', {\n detail: { audioLevel: level },\n bubbles: true,\n composed: true,\n }),\n );\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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioService.js","sourceRoot":"","sources":["../src/audioService.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,YAAY;IAKvB,YAAY,WAAwB;QAClC,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC;QACtE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;QACnD,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QAC7B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAEM,aAAa;QAClB,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;QAC/C,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,UAAU,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;YAC9C,GAAG,IAAI,UAAU,GAAG,UAAU,CAAC;QACjC,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,CAAC;IACvC,CAAC;CACF","sourcesContent":["export class AudioService {\n private audioContext: AudioContext;\n\n private analyser: AnalyserNode;\n\n constructor(mediaStream: MediaStream) {\n this.audioContext = new AudioContext();\n const source = this.audioContext.createMediaStreamSource(mediaStream);\n this.analyser = this.audioContext.createAnalyser();\n this.analyser.fftSize = 8192;\n source.connect(this.analyser);\n }\n\n public getAudioLevel(): number {\n const bufferLength = this.analyser.fftSize;\n const dataArray = new Uint8Array(bufferLength);\n this.analyser.getByteTimeDomainData(dataArray);\n let sum = 0;\n for (let i = 0; i < bufferLength; i += 1) {\n const normalized = (dataArray[i] - 128) / 128;\n sum += normalized * normalized;\n }\n return Math.sqrt(sum / bufferLength);\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio-visualiser.js","sourceRoot":"","sources":["../../src/components/audio-visualiser.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGrD,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,UAAU;IAAxC;;QACuB,UAAK,GAAG,CAAC,CAAC,CAAC,gCAAgC;QAE1C,WAAM,GAAG,IAAI,CAAC;IA0C7C,CAAC;IAbC,MAAM;QACJ,gFAAgF;QAChF,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAA;8BACM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;OACzD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAA;8BACe,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ;KACjE,CAAC;IACJ,CAAC;;AAvCM,sBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBlB,AAzBY,CAyBX;AA7B0B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;8CAAW;AAET;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;+CAAe;AAHhC,eAAe;IAD3B,aAAa,CAAC,kBAAkB,CAAC;GACrB,eAAe,CA6C3B","sourcesContent":["import { LitElement, html, css } from 'lit';\nimport { property, customElement } from 'lit/decorators.js';\n\n@customElement('audio-visualiser')\nexport class AudioVisualiser extends LitElement {\n @property({ type: Number }) level = 0; // expects a value from 0 to 100\n\n @property({ type: Boolean }) active = true;\n\n static styles = css`\n :host {\n height: 100%;\n }\n .container {\n display: flex;\n width: 8px;\n flex-direction: column-reverse; /* Bottom-up stacking */\n height: 100%;\n gap: 1px;\n opacity: 0.5;\n &.active {\n opacity: 1;\n }\n }\n .segment {\n flex: 1;\n background-color: var(--action-accent-text-color);\n transition: background-color 0.25s;\n border-radius: 1px;\n opacity: 0.5;\n }\n .segment.active {\n opacity: 1;\n }\n `;\n\n render() {\n // Each segment represents 20%. Using Math.ceil to fill segments optimistically.\n const activeSegments = Math.round(this.level * 5);\n const segments = [];\n for (let i = 0; i < 5; i += 1) {\n segments.push(html`\n <div class=\"segment ${i < activeSegments ? 'active' : ''}\"></div>\n `);\n }\n return html`\n <div class=\"container ${this.active ? 'active' : ''}\">${segments}</div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'audio-visualiser': AudioVisualiser;\n }\n}\n"]}
|
|
@@ -0,0 +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,MAAM,mBAAmB,CAAC;AAE5D,OAAO,YAAY,MAAM,mBAAmB,CAAC;AAC7C,OAAO,YAAY,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,aAAa,MAAM,mBAAmB,CAAC;AAGvC,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAArC;;QAEL,YAAO,GAAsB,EAAE,CAAC;QAGhC,mBAAc,GAAW,EAAE,CAAC;QAG5B,qBAAgB,GAAW,EAAE,CAAC;QAG9B,qBAAgB,GAAY,KAAK,CAAC;IA2HpC,CAAC;IAjFS,aAAa,CAAC,QAAgB;QACpC,IAAI,CAAC,cAAc,GAAG,QAAQ,CAAC;QAC/B,yBAAyB;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAC/D,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,0BAA0B,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;cAOD,IAAI,CAAC,gBAAgB;YACrB,CAAC,CAAC,IAAI,CAAA;;;;iBAIH;YACH,CAAC,CAAC,EAAE;;;;;;;;0BAQQ,CAAC,CAAQ,EAAE,EAAE;YACrB,IAAI,CAAC,aAAa,CAAE,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC,CAAC;QAC5D,CAAC;4BACW,IAAI,CAAC,gBAAgB;;kBAE/B,IAAI,CAAC,OAAO,CAAC,GAAG,CAChB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAA;;8BAEF,MAAM,CAAC,QAAQ;kCACX,IAAI,CAAC,cAAc,KAAK,MAAM,CAAC,QAAQ;;wBAEjD,MAAM,CAAC,KAAK,IAAI,gBAAgB;;mBAErC,CACF;;;;;;;;;;0BAUS,CAAC,CAAQ,EAAE,EAAE;YACrB,IAAI,CAAC,aAAa,CAAE,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC,CAAC;QAC5D,CAAC;4BACW,IAAI,CAAC,gBAAgB;;kBAE/B,mBAAmB,CAAC,GAAG,CACvB,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAA;;8BAEJ,QAAQ;kCACJ,IAAI,CAAC,gBAAgB,KAAK,QAAQ;;wBAE5C,eAAe,CAAC,QAAQ,CAAC;;mBAE9B,CACF;;;;;;KAMZ,CAAC;IACJ,CAAC;;AAxHM,mBAAM,GAAmB;IAC9B,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAiCF;IACD,YAAY;IACZ,YAAY;IACZ,aAAa;CACd,AAtCY,CAsCX;AAjDF;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;6CACM;AAGhC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oDACC;AAG5B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;sDACG;AAG9B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;sDACM;AAXvB,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CAsIxB","sourcesContent":["// mic-selector.ts\nimport { LitElement, html, css, TemplateResult, CSSResultGroup } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport ButtonStyles from '../styles/buttons';\nimport SelectStyles from '../styles/select';\nimport { LANGUAGES_SUPPORTED } from '../constants';\nimport { getLanguageName } from '../utils';\nimport CalloutStyles from '../styles/callout';\n\n@customElement('settings-menu')\nexport class SettingsMenu extends LitElement {\n @property({ type: Array })\n devices: MediaDeviceInfo[] = [];\n\n @property({ type: String })\n selectedDevice: string = '';\n\n @property({ type: String })\n selectedLanguage: string = '';\n\n @property({ type: Boolean })\n settingsDisabled: boolean = false;\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;\n position-visibility: always;\n /* inset: unset; */\n transform: translateX(40%);\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 this.selectedDevice = deviceId;\n // Find the device object\n const device = this.devices.find(d => d.deviceId === deviceId);\n this.dispatchEvent(\n new CustomEvent('recording-device-changed', {\n detail: device,\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 orange\">\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.deviceId}\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"]}
|
|
@@ -0,0 +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';\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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.js","sourceRoot":"","sources":["../../src/icons/icons.ts"],"names":[],"mappings":";AAAA,yCAAyC;AACzC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAG3C,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,UAAU;IACvC,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;KAmBV,CAAC;IACJ,CAAC;CACF,CAAA;AAvBY,SAAS;IADrB,aAAa,CAAC,aAAa,CAAC;GAChB,SAAS,CAuBrB;;AAGM,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IACxC,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;WAoBJ,CAAC;IACV,CAAC;CACF,CAAA;AAxBY,UAAU;IADtB,aAAa,CAAC,cAAc,CAAC;GACjB,UAAU,CAwBtB;;AAGM,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;IAC3C,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;KAkBV,CAAC;IACJ,CAAC;CACF,CAAA;AAtBY,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CAsBzB;;AAEM,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAC1C,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;WAkBJ,CAAC;IACV,CAAC;CACF,CAAA;AAtBY,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CAsBxB;;AAGM,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,UAAU;IAehD,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;WAeJ,CAAC;IACV,CAAC;;AA/BM,yBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;GAYlB,AAZY,CAYX;AAbS,kBAAkB;IAD9B,aAAa,CAAC,sBAAsB,CAAC;GACzB,kBAAkB,CAiC9B","sourcesContent":["/* eslint-disable max-classes-per-file */\nimport { LitElement, css, html } from 'lit';\nimport { customElement } from 'lit/decorators.js';\n\n@customElement('icon-mic-on')\nexport class IconMicOn extends LitElement {\n render() {\n return html`\n <div style=\"display: flex\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-mic\"\n >\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\" />\n </svg>\n </div>\n `;\n }\n}\n\n@customElement('icon-mic-off')\nexport class IconMicOff extends LitElement {\n render() {\n return html` <div style=\"display: flex\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-mic-off\"\n >\n <line x1=\"2\" x2=\"22\" y1=\"2\" y2=\"22\" />\n <path d=\"M18.89 13.23A7.12 7.12 0 0 0 19 12v-2\" />\n <path d=\"M5 10v2a7 7 0 0 0 12 5\" />\n <path d=\"M15 9.34V5a3 3 0 0 0-5.68-1.33\" />\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12\" />\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\" />\n </svg>\n </div>`;\n }\n}\n\n@customElement('icon-recording')\nexport class IconRecording extends LitElement {\n render() {\n return html`\n <div style=\"display: flex;\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-circle-stop\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <rect x=\"9\" y=\"9\" width=\"6\" height=\"6\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </div>\n `;\n }\n}\n@customElement('icon-settings')\nexport class IconSettings extends LitElement {\n render() {\n return html`<div style=\"display: flex\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-settings-2\"\n >\n <path d=\"M20 7h-9\" />\n <path d=\"M14 17H5\" />\n <circle cx=\"17\" cy=\"17\" r=\"3\" />\n <circle cx=\"7\" cy=\"7\" r=\"3\" />\n </svg>\n </div>`;\n }\n}\n\n@customElement('icon-loading-spinner')\nexport class IconLoadingSpinner extends LitElement {\n static styles = css`\n @keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n .spin {\n animation: spin 1s linear infinite;\n }\n `;\n\n render() {\n return html`<div style=\"display: flex\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-loader-circle spin\"\n >\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n </div>`;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/icons/index.ts"],"names":[],"mappings":"","sourcesContent":[""]}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAE9C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;IAC3C,cAAc,CAAC,MAAM,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;AAC3D,CAAC;AAED,eAAe,cAAc,CAAC","sourcesContent":["import CortiDictation from \"./CortiDictation\";\n\nif (!customElements.get(\"corti-dictation\")) {\n customElements.define(\"corti-dictation\", CortiDictation);\n}\n\nexport default CortiDictation;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComponentStyles.js","sourceRoot":"","sources":["../../src/styles/ComponentStyles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,eAAe,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgD1B,CAAC;AAEF,eAAe,eAAe,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst ComponentStyles = css`\n .wrapper {\n background-color: 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 padding: var(--card-padding);\n display: flex;\n width: min-content;\n gap: 4px;\n height: 46px;\n box-sizing: border-box;\n overflow: hidden;\n }\n h2 {\n margin: 0 0 10px;\n font-size: 1rem;\n font-weight: 500;\n }\n label {\n font-size: 0.9rem;\n margin-right: 8px;\n }\n select {\n padding: 4px 6px;\n font-size: 0.9rem;\n border: 1px solid var(--card-border-color);\n border-radius: 4px;\n background-color: var(--card-background);\n color: inherit;\n }\n\n .visualiser {\n width: 16px;\n height: 100%;\n background: var(--visualiser-background);\n margin-top: 8px;\n border-radius: 5px;\n overflow: hidden;\n display: flex;\n align-items: flex-end;\n }\n .level {\n height: 100%;\n width: 100%;\n background: var(--visualiser-level-color);\n transition: width 0.1s ease-in-out;\n }\n`;\n\nexport default ComponentStyles;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buttons.js","sourceRoot":"","sources":["../../src/styles/buttons.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,YAAY,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDvB,CAAC;AAEF,eAAe,YAAY,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst ButtonStyles = css`\n /* Default (plain) button styling */\n button,\n .button {\n background: var(--action-plain-background);\n /* border: 1px solid var(--action-plain-border-color); */\n border: none;\n color: var(--component-text-color);\n cursor: pointer;\n padding: 8px;\n border-radius: var(--card-inner-border-radius);\n display: inline-flex;\n gap: 4px;\n align-items: center;\n justify-content: center;\n transition: background 0.3s ease;\n font-family: var(--component-font-family);\n }\n\n button:hover,\n .button:hover {\n background: var(--action-plain-background-hover);\n }\n\n button:focus-visible {\n outline: 2px solid var(--action-accent-background);\n outline-offset: 2px;\n }\n\n /* Accent variant */\n button.accent,\n .button.accent {\n background: var(--action-accent-background);\n color: var(--action-accent-text-color);\n border: none;\n }\n\n button.accent:hover,\n .button.accent:hover {\n background: var(--action-accent-background-hover);\n }\n\n /* Accent variant */\n button.red,\n .button.red {\n background: var(--action-red-background);\n color: var(--action-red-text-color);\n border: none;\n }\n\n button.red:hover,\n .button.red:hover {\n background: var(--action-red-background-hover);\n }\n`;\n\nexport default ButtonStyles;\n"]}
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;CAsBxB,CAAC;AAEF,eAAe,aAAa,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst CalloutStyles = css`\n .callout {\n background: var(--callout-accent-background);\n border: 1px solid var(--callout-accent-border);\n color: var(--callout-accent-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: flex-start;\n &.red {\n background: var(--callout-red-background);\n border: 1px solid var(--callout-red-border);\n color: var(--callout-red-text);\n }\n &.orange {\n background: var(--callout-orange-background);\n border: 1px solid var(--callout-orange-border);\n color: var(--callout-orange-text);\n }\n }\n`;\n\nexport default CalloutStyles;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/styles/select.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,YAAY,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCvB,CAAC;AAEF,eAAe,YAAY,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst SelectStyles = css`\n label {\n display: block;\n font-size: 0.8rem;\n padding-bottom: 0.5rem;\n font-weight: 500;\n color: var(--component-text-color);\n pointer-events: none;\n }\n select {\n background: var(--card-background);\n color: var(--component-text-color);\n border: 1px solid var(--card-border-color);\n padding: var(--card-padding);\n border-radius: var(--card-inner-border-radius);\n outline: none;\n width: 100%;\n }\n\n select:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n select:hover {\n background: var(--action-plain-background-hover);\n }\n\n select:focus-visible {\n outline: 2px solid var(--action-accent-background);\n /* outline-offset: 2px; */\n }\n`;\n\nexport default SelectStyles;\n"]}
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEtB,CAAC;AAEF,eAAe,WAAW,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst ThemeStyles = css`\n :host {\n /* Component Defaults */\n --component-font-family: 'Segoe UI', Roboto, sans-serif;\n --component-text-color: #333;\n\n /* Card Defaults */\n --card-background: #fff;\n --card-border-color: #ddd;\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: #ccc;\n --action-plain-background-hover: #ddd;\n\n --action-accent-background: #007bff;\n --action-accent-background-hover: #0056b3;\n --action-accent-text-color: #fff;\n\n --action-red-background: #dc3545;\n --action-red-background-hover: #bd2130;\n --action-red-text-color: #fff;\n\n /* Callout Defaults */\n --callout-accent-background: #007bff33;\n --callout-accent-border: #007bff99;\n --callout-accent-text: #007bff;\n\n --callout-red-background: #dc354533;\n --callout-red-border: #dc354599;\n --callout-red-text: #dc3545;\n\n --callout-orange-background: #fd7e1433;\n --callout-orange-border: #fd7e1499;\n --callout-orange-text: #fd7e14;\n\n /* Visualiser Defaults */\n --visualiser-background: #e0e0e0;\n --visualiser-level-color: #28a745;\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n /* Component Dark */\n --component-text-color: #eee;\n\n /* Card Dark */\n --card-background: #333;\n --card-border-color: #555;\n\n /* Actions Dark */\n --action-plain-border-color: #555;\n --action-plain-background: #333;\n --action-plain-background-hover: #444;\n\n --action-accent-background: #0056b3;\n --action-accent-background-hover: #003d80;\n\n /* Visualiser Dark */\n --visualiser-background: #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"]}
|
|
@@ -0,0 +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\nexport interface Command {\n command: string;\n action: string;\n keywords: string[];\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 token?: string;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,IAAI,IAAI,CAAC;IAC9C,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,UAAU,CAAC,EAAE;QACvD,IAAI,EAAE,UAAU;KACjB,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC;IACnD,OAAO,YAAY,IAAI,YAAY,CAAC;AACtC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,+CAA+C;QAC/C,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1E,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAClD,OAAO;QACT,CAAC;QAED,MAAM,gBAAgB,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC;YACzD,oCAAoC;YACpC,IAAI,EAAE,YAA8B;SACrC,CAAC,CAAC;QAEH,IAAI,gBAAgB,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1E,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;aAAM,IAAI,gBAAgB,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,kDAAkD,EAAE,KAAK,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IAInC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,gBAAgB,EAAE,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,gBAAgB,EAAE,CAAC;IAEzB,IAAI,CAAC;QACH,0EAA0E;QAC1E,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;QAChE,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;QAC5E,MAAM,eAAe,GACnB,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;QACjE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzB,CAAC;AACH,CAAC","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 defaultDeviceId?: string;\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 defaultDeviceId =\n audioDevices.length > 0 ? audioDevices[0].deviceId : undefined;\n return { devices: audioDevices, defaultDeviceId };\n } catch (error) {\n console.error('Error enumerating devices:', error);\n return { devices: [] };\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
"name": "@corti/dictation-web",
|
|
3
3
|
"description": "Web component for Corti Dictation",
|
|
4
4
|
"author": "Corti ApS",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.2",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"main": "dist/
|
|
8
|
-
"module": "dist/
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
9
|
"exports": {
|
|
10
|
-
".": "./dist/
|
|
11
|
-
"./corti-dictation.js": "./dist/src/corti-dictation.js"
|
|
10
|
+
".": "./dist/index.js"
|
|
12
11
|
},
|
|
12
|
+
"files": ["dist"],
|
|
13
13
|
"scripts": {
|
|
14
14
|
"analyze": "cem analyze --litelement",
|
|
15
|
-
"start": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"web-dev-server\"",
|
|
16
15
|
"build": "tsc && npm run analyze -- --exclude dist",
|
|
16
|
+
"start": "npm run build && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"web-dev-server\"",
|
|
17
17
|
"prepublish": "tsc && npm run analyze -- --exclude dist",
|
|
18
18
|
"lint": "eslint --ext .ts,.tsx src --ignore-path .gitignore && prettier \"src/**/*.ts\" --check --ignore-path .gitignore",
|
|
19
19
|
"format": "eslint --ext .ts,.tsx src --fix --ignore-path .gitignore && prettier \"src/**/*.ts\" --write --ignore-path .gitignore",
|
package/.editorconfig
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# EditorConfig helps developers define and maintain consistent
|
|
2
|
-
# coding styles between different editors and IDEs
|
|
3
|
-
# editorconfig.org
|
|
4
|
-
|
|
5
|
-
root = true
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
[*]
|
|
9
|
-
|
|
10
|
-
# Change these settings to your own preference
|
|
11
|
-
indent_style = space
|
|
12
|
-
indent_size = 2
|
|
13
|
-
|
|
14
|
-
# We recommend you to keep these unchanged
|
|
15
|
-
end_of_line = lf
|
|
16
|
-
charset = utf-8
|
|
17
|
-
trim_trailing_whitespace = true
|
|
18
|
-
insert_final_newline = true
|
|
19
|
-
|
|
20
|
-
[*.md]
|
|
21
|
-
trim_trailing_whitespace = false
|
|
22
|
-
|
|
23
|
-
[*.json]
|
|
24
|
-
indent_size = 2
|
|
25
|
-
|
|
26
|
-
[*.{html,js,md}]
|
|
27
|
-
block_comment_start = /**
|
|
28
|
-
block_comment = *
|
|
29
|
-
block_comment_end = */
|
package/.eslintrc.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"parser": "@typescript-eslint/parser",
|
|
3
|
-
"extends": [
|
|
4
|
-
"eslint:recommended",
|
|
5
|
-
"plugin:@typescript-eslint/recommended"
|
|
6
|
-
],
|
|
7
|
-
"plugins": ["@typescript-eslint", "html"],
|
|
8
|
-
"overrides": [
|
|
9
|
-
{
|
|
10
|
-
"files": ["*.ts", "*.tsx"],
|
|
11
|
-
"rules": {
|
|
12
|
-
"import/extensions": "off"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
]
|
|
16
|
-
}
|
package/.husky/pre-commit
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
./node_modules/.bin/lint-staged
|
package/.storybook/main.js
DELETED
package/demo/index.html
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en-GB">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
|
-
<style>
|
|
7
|
-
body {
|
|
8
|
-
background: #fafafa;
|
|
9
|
-
font-family: Arial, sans-serif;
|
|
10
|
-
margin: 20px;
|
|
11
|
-
}
|
|
12
|
-
/* Dark mode support */
|
|
13
|
-
@media (prefers-color-scheme: dark) {
|
|
14
|
-
body {
|
|
15
|
-
background: #1c1e2b;
|
|
16
|
-
color: #fff;
|
|
17
|
-
}
|
|
18
|
-
textarea {
|
|
19
|
-
background: #333;
|
|
20
|
-
color: #fff;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
textarea {
|
|
24
|
-
width: 100%;
|
|
25
|
-
max-width: 800px;
|
|
26
|
-
height: 150px;
|
|
27
|
-
margin-top: 20px;
|
|
28
|
-
padding: 10px;
|
|
29
|
-
font-size: 14px;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
#interimTranscript {
|
|
33
|
-
background: #333333aa;
|
|
34
|
-
color: #fff;
|
|
35
|
-
font-size: 24px;
|
|
36
|
-
margin-top: 10px;
|
|
37
|
-
position: fixed;
|
|
38
|
-
bottom: 40px;
|
|
39
|
-
left: 50%;
|
|
40
|
-
transform: translateX(-50%);
|
|
41
|
-
padding: 10px;
|
|
42
|
-
display: none;
|
|
43
|
-
}
|
|
44
|
-
</style>
|
|
45
|
-
</head>
|
|
46
|
-
<body>
|
|
47
|
-
<!-- Directly using the custom element without Lit -->
|
|
48
|
-
<corti-dictation></corti-dictation>
|
|
49
|
-
|
|
50
|
-
<!-- Textarea to display transcript text -->
|
|
51
|
-
<textarea id="transcript" placeholder="Transcript will appear here..."></textarea>
|
|
52
|
-
|
|
53
|
-
<div id="interimTranscript"></div>
|
|
54
|
-
|
|
55
|
-
<script type="module">
|
|
56
|
-
// Import the custom component (assumes corti-dictation.js registers the element)
|
|
57
|
-
import '../dist/src/corti-dictation.js';
|
|
58
|
-
|
|
59
|
-
// Server configuration for the dictation component
|
|
60
|
-
const serverConfig = {
|
|
61
|
-
environment: "a",
|
|
62
|
-
tenant: "a",
|
|
63
|
-
token: "a",
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// Get the corti-dictation element and assign the server config
|
|
67
|
-
const dictationEl = document.querySelector('corti-dictation');
|
|
68
|
-
dictationEl.serverConfig = serverConfig;
|
|
69
|
-
|
|
70
|
-
// Listen to events from the dictation component
|
|
71
|
-
dictationEl.addEventListener('recording-state-changed', (e) => {
|
|
72
|
-
console.log('Recording state:', e.detail.state);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
dictationEl.addEventListener('recording-device-changed', (e) => {
|
|
76
|
-
console.log('Recording Device Changed:', e.detail);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
dictationEl.addEventListener('error', (e) => {
|
|
80
|
-
console.error(e.detail);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// Update the textarea with transcript text when received
|
|
84
|
-
dictationEl.addEventListener('transcript', (e) => {
|
|
85
|
-
const {data} = e.detail
|
|
86
|
-
const transcriptArea = document.getElementById('transcript');
|
|
87
|
-
const interimTranscript = document.getElementById('interimTranscript');
|
|
88
|
-
if(data.isFinal){
|
|
89
|
-
transcriptArea.value += data.text + " ";
|
|
90
|
-
interimTranscript.style.display = 'none';
|
|
91
|
-
} else {
|
|
92
|
-
interimTranscript.style.display = 'block';
|
|
93
|
-
interimTranscript.innerText = data.rawTranscriptText;
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
</script>
|
|
97
|
-
</body>
|
|
98
|
-
</html>
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { LitElement } from 'lit';
|
|
2
|
-
import './components/settings-menu';
|
|
3
|
-
import './components/audio-visualiser';
|
|
4
|
-
import './icons/icons';
|
|
5
|
-
import { DictationConfig, ServerConfig } from './types';
|
|
6
|
-
export declare class CortiDictation extends LitElement {
|
|
7
|
-
static styles: import("lit").CSSResult[];
|
|
8
|
-
devices: MediaDeviceInfo[];
|
|
9
|
-
recordingState: string;
|
|
10
|
-
dictationConfig: DictationConfig;
|
|
11
|
-
serverConfig: ServerConfig;
|
|
12
|
-
private _audioLevel;
|
|
13
|
-
private recorderManager;
|
|
14
|
-
connectedCallback(): Promise<void>;
|
|
15
|
-
toggleRecording(): void;
|
|
16
|
-
_toggleRecording(): void;
|
|
17
|
-
_onRecordingDeviceChanged(event: Event): Promise<void>;
|
|
18
|
-
render(): import("lit-html").TemplateResult<1>;
|
|
19
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { __decorate } from "tslib";
|
|
2
|
-
// corti-dictation.ts
|
|
3
|
-
import { html, LitElement } from 'lit';
|
|
4
|
-
import { property, state } from 'lit/decorators.js';
|
|
5
|
-
import { RecorderManager } from './RecorderManager';
|
|
6
|
-
import './components/settings-menu';
|
|
7
|
-
import './components/audio-visualiser';
|
|
8
|
-
import './icons/icons';
|
|
9
|
-
import ThemeStyles from './styles/theme';
|
|
10
|
-
import ButtonStyles from './styles/buttons';
|
|
11
|
-
import { componentStyles } from './componentStyles';
|
|
12
|
-
import { DEFAULT_DICTATION_CONFIG } from './constants';
|
|
13
|
-
import CalloutStyles from './styles/callout';
|
|
14
|
-
export class CortiDictation extends LitElement {
|
|
15
|
-
constructor() {
|
|
16
|
-
super(...arguments);
|
|
17
|
-
this.devices = [];
|
|
18
|
-
this.recordingState = 'stopped';
|
|
19
|
-
this.dictationConfig = DEFAULT_DICTATION_CONFIG;
|
|
20
|
-
this.serverConfig = {};
|
|
21
|
-
this._audioLevel = 0;
|
|
22
|
-
this.recorderManager = new RecorderManager();
|
|
23
|
-
}
|
|
24
|
-
async connectedCallback() {
|
|
25
|
-
super.connectedCallback();
|
|
26
|
-
await this.recorderManager.initialize();
|
|
27
|
-
this.devices = this.recorderManager.devices;
|
|
28
|
-
// Map event names to any extra handling logic
|
|
29
|
-
const eventHandlers = {
|
|
30
|
-
'recording-state-changed': (e) => {
|
|
31
|
-
this.recordingState = e.detail.state;
|
|
32
|
-
},
|
|
33
|
-
'audio-level-changed': (e) => {
|
|
34
|
-
this._audioLevel = e.detail.audioLevel;
|
|
35
|
-
this.requestUpdate();
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
const eventsToRelay = [
|
|
39
|
-
'recording-state-changed',
|
|
40
|
-
'audio-level-changed',
|
|
41
|
-
'audio-packet',
|
|
42
|
-
'transcript',
|
|
43
|
-
];
|
|
44
|
-
eventsToRelay.forEach((eventName) => {
|
|
45
|
-
this.recorderManager.addEventListener(eventName, (e) => {
|
|
46
|
-
const customEvent = e;
|
|
47
|
-
// Perform any additional handling if defined
|
|
48
|
-
if (eventHandlers[eventName]) {
|
|
49
|
-
eventHandlers[eventName](customEvent);
|
|
50
|
-
}
|
|
51
|
-
// Re-dispatch the event from the component
|
|
52
|
-
this.dispatchEvent(new CustomEvent(eventName, {
|
|
53
|
-
detail: customEvent.detail,
|
|
54
|
-
bubbles: true,
|
|
55
|
-
composed: true,
|
|
56
|
-
}));
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
toggleRecording() {
|
|
61
|
-
this._toggleRecording();
|
|
62
|
-
}
|
|
63
|
-
_toggleRecording() {
|
|
64
|
-
if (this.recordingState === 'recording') {
|
|
65
|
-
this.recorderManager.stopRecording();
|
|
66
|
-
}
|
|
67
|
-
else if (this.recordingState === 'stopped') {
|
|
68
|
-
this.recorderManager.startRecording({ dictationConfig: this.dictationConfig, serverConfig: this.serverConfig });
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
// Handle device change events if needed
|
|
72
|
-
async _onRecordingDeviceChanged(event) {
|
|
73
|
-
const customEvent = event;
|
|
74
|
-
this.recorderManager.selectedDevice = customEvent.detail.deviceId;
|
|
75
|
-
if (this.recordingState === 'recording') {
|
|
76
|
-
await this.recorderManager.stopRecording();
|
|
77
|
-
await this.recorderManager.startRecording({ dictationConfig: this.dictationConfig, serverConfig: this.serverConfig });
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
render() {
|
|
81
|
-
const isConfigured = this.serverConfig && this.serverConfig.token && this.serverConfig.environment && this.serverConfig.tenant;
|
|
82
|
-
if (!isConfigured) {
|
|
83
|
-
return html `
|
|
84
|
-
<div class="wrapper">
|
|
85
|
-
<div class="callout red tiny">
|
|
86
|
-
Please configure the server settings in the parent component.
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
`;
|
|
90
|
-
}
|
|
91
|
-
const isLoading = this.recordingState === 'initializing' ||
|
|
92
|
-
this.recordingState === 'stopping';
|
|
93
|
-
const isRecording = this.recordingState === 'recording';
|
|
94
|
-
return html `
|
|
95
|
-
<div class="wrapper">
|
|
96
|
-
<button
|
|
97
|
-
@click=${this._toggleRecording}
|
|
98
|
-
class=${isRecording ? 'red' : 'accent'}
|
|
99
|
-
>
|
|
100
|
-
${isLoading
|
|
101
|
-
? html `<icon-loading-spinner></icon-loading-spinner>`
|
|
102
|
-
: isRecording
|
|
103
|
-
? html `<icon-recording></icon-recording>`
|
|
104
|
-
: html `<icon-mic-on></icon-mic-on>`}
|
|
105
|
-
<audio-visualiser
|
|
106
|
-
.level=${this._audioLevel}
|
|
107
|
-
.active=${isRecording}
|
|
108
|
-
></audio-visualiser>
|
|
109
|
-
</button>
|
|
110
|
-
|
|
111
|
-
<settings-menu
|
|
112
|
-
.devices=${this.devices}
|
|
113
|
-
.selectedDevice=${this.recorderManager.selectedDevice}
|
|
114
|
-
?settingsDisabled=${this.recordingState !== 'stopped'}
|
|
115
|
-
@recording-device-changed=${this._onRecordingDeviceChanged}
|
|
116
|
-
></settings-menu>
|
|
117
|
-
</div>
|
|
118
|
-
`;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
CortiDictation.styles = [ButtonStyles, ThemeStyles, componentStyles, CalloutStyles];
|
|
122
|
-
__decorate([
|
|
123
|
-
property({ type: Array })
|
|
124
|
-
], CortiDictation.prototype, "devices", void 0);
|
|
125
|
-
__decorate([
|
|
126
|
-
property({ type: String, reflect: true })
|
|
127
|
-
], CortiDictation.prototype, "recordingState", void 0);
|
|
128
|
-
__decorate([
|
|
129
|
-
property({ type: Object })
|
|
130
|
-
], CortiDictation.prototype, "dictationConfig", void 0);
|
|
131
|
-
__decorate([
|
|
132
|
-
property({ type: Object })
|
|
133
|
-
], CortiDictation.prototype, "serverConfig", void 0);
|
|
134
|
-
__decorate([
|
|
135
|
-
state()
|
|
136
|
-
], CortiDictation.prototype, "_audioLevel", void 0);
|
|
137
|
-
//# sourceMappingURL=CortiDictation.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CortiDictation.js","sourceRoot":"","sources":["../../src/CortiDictation.ts"],"names":[],"mappings":"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","sourcesContent":["// corti-dictation.ts\nimport { html, LitElement, css } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { RecorderManager } from './RecorderManager';\nimport './components/settings-menu';\nimport './components/audio-visualiser';\nimport './icons/icons';\nimport ThemeStyles from './styles/theme';\nimport ButtonStyles from './styles/buttons';\nimport { componentStyles } from './componentStyles';\nimport { DictationConfig, ServerConfig } from './types';\nimport { DEFAULT_DICTATION_CONFIG } from './constants';\nimport CalloutStyles from './styles/callout';\n\nexport class CortiDictation extends LitElement {\n static styles = [ButtonStyles, ThemeStyles, componentStyles, CalloutStyles];\n\n @property({ type: Array })\n devices: MediaDeviceInfo[] = [];\n\n @property({ type: String, reflect: true })\n recordingState = 'stopped';\n\n @property({ type: Object })\n dictationConfig: DictationConfig = DEFAULT_DICTATION_CONFIG;\n\n @property({ type: Object })\n serverConfig: ServerConfig = {};\n\n @state()\n private _audioLevel = 0;\n\n private recorderManager = new RecorderManager();\n\n async connectedCallback() {\n super.connectedCallback();\n await this.recorderManager.initialize();\n this.devices = this.recorderManager.devices;\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 'audio-level-changed': (e) => {\n this._audioLevel = e.detail.audioLevel;\n this.requestUpdate();\n },\n };\n \n const eventsToRelay = [\n 'recording-state-changed',\n 'audio-level-changed',\n 'audio-packet',\n 'transcript',\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 _toggleRecording() {\n if (this.recordingState === 'recording') {\n this.recorderManager.stopRecording();\n } else if (this.recordingState === 'stopped') {\n this.recorderManager.startRecording({dictationConfig: this.dictationConfig, serverConfig: this.serverConfig});\n }\n }\n\n // Handle device change events if needed\n async _onRecordingDeviceChanged(event: Event) {\n const customEvent = event as CustomEvent;\n this.recorderManager.selectedDevice = customEvent.detail.deviceId;\n if (this.recordingState === 'recording') {\n await this.recorderManager.stopRecording();\n await this.recorderManager.startRecording({dictationConfig: this.dictationConfig, serverConfig: this.serverConfig});\n }\n }\n\n render() {\n\n const isConfigured = this.serverConfig && this.serverConfig.token && this.serverConfig.environment && this.serverConfig.tenant;\n if (!isConfigured) {\n return html`\n <div class=\"wrapper\">\n <div class=\"callout red tiny\">\n Please configure the server settings in the parent component.\n </div>\n </div>\n `;\n }\n\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 .devices=${this.devices}\n .selectedDevice=${this.recorderManager.selectedDevice}\n ?settingsDisabled=${this.recordingState !== 'stopped'}\n @recording-device-changed=${this._onRecordingDeviceChanged}\n ></settings-menu>\n </div>\n `;\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DictationService.js","sourceRoot":"","sources":["../../src/DictationService.ts"],"names":[],"mappings":"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","sourcesContent":["import { DictationConfig, ServerConfig } from './types';\n\nexport class DictationService extends EventTarget {\n private mediaRecorder: MediaRecorder;\n\n private webSocket!: WebSocket;\n\n private serverConfig!: ServerConfig;\n\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 this.mediaRecorder.ondataavailable = event => {\n // if webSocket is open, send the data\n if (this.webSocket?.readyState === WebSocket.OPEN) {\n this.webSocket.send(event.data);\n }\n };\n }\n\n public startRecording() {\n const url = `wss://api.${this.serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${this.serverConfig.tenant}&token=Bearer%20${this.serverConfig.token}`;\n this.webSocket = new WebSocket(url);\n this.webSocket.onopen = () => {\n this.webSocket.send(\n JSON.stringify({\n type: 'config',\n configuration: this.dictationConfig,\n }),\n );\n };\n this.webSocket.onmessage = event => {\n const message = JSON.parse(event.data);\n if (message.type === 'config') {\n this.mediaRecorder.start(250);\n } else if (message.type === 'transcript') {\n this.dispatchEvent(\n new CustomEvent('transcript', {\n detail: message,\n bubbles: true,\n composed: true,\n }),\n );\n }\n };\n this.webSocket.onerror = event => {\n this.dispatchEvent(\n new CustomEvent('error', {\n detail: event,\n bubbles: true,\n composed: true,\n }),\n );\n };\n this.webSocket.onclose = (event) => {\n this.dispatchEvent(\n new CustomEvent('stream-closed', {\n detail: event,\n bubbles: true,\n composed: true,\n }),\n );\n };\n }\n\n public async stopRecording() {\n this.mediaRecorder.stop();\n\n if (this.webSocket?.readyState === WebSocket.OPEN) {\n this.webSocket.send(\n JSON.stringify({\n type: 'end',\n }),\n );\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 implementation should be replaced by handling a proper 'ended' message from the server\n this.webSocket.onclose = () => {\n this.webSocket?.close();\n clearTimeout(timeOut);\n };\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RecorderManager.js","sourceRoot":"","sources":["../../src/RecorderManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { getAudioDevices } from './utils';\nimport { AudioService } from './audioService';\nimport { DictationService } from './DictationService';\nimport type { DictationConfig, RecordingState, ServerConfig } from './types';\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\n async startRecording(params: {\n dictationConfig: DictationConfig;\n serverConfig: ServerConfig;\n }) {\n this._updateRecordingState('initializing');\n try {\n this._mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: { deviceId: this.selectedDevice },\n });\n this._audioService = new AudioService(this._mediaStream);\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 );\n this._dictationService.addEventListener('stream-closed', () => this.stopRecording());\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 } catch (error) {\n this.dispatchEvent(\n new CustomEvent('error', {\n detail: error,\n bubbles: true,\n composed: true,\n }),\n );\n this._updateRecordingState('stopped');\n return;\n }\n\n this._dictationService?.startRecording();\n this._updateRecordingState('recording');\n this._visualiserInterval = window.setInterval(() => {\n const level = this._audioService\n ? this._audioService.getAudioLevel() * 3\n : 0;\n this.dispatchEvent(\n new CustomEvent('audio-level-changed', {\n detail: { audioLevel: level },\n bubbles: true,\n composed: true,\n }),\n );\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,17 +0,0 @@
|
|
|
1
|
-
import type { RecordingState } from './types';
|
|
2
|
-
export declare class RecorderManager extends EventTarget {
|
|
3
|
-
devices: MediaDeviceInfo[];
|
|
4
|
-
selectedDevice: string;
|
|
5
|
-
recordingState: RecordingState;
|
|
6
|
-
private _mediaStream;
|
|
7
|
-
private _audioService;
|
|
8
|
-
private _dictationService;
|
|
9
|
-
private _visualiserInterval?;
|
|
10
|
-
initialize(): Promise<{
|
|
11
|
-
devices: MediaDeviceInfo[];
|
|
12
|
-
defaultDeviceId?: string;
|
|
13
|
-
}>;
|
|
14
|
-
startRecording(): Promise<void>;
|
|
15
|
-
stopRecording(): Promise<void>;
|
|
16
|
-
private _updateRecordingState;
|
|
17
|
-
}
|