dsh-live-voice 0.5.0 → 0.5.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/README.md +20 -112
- package/lib/client.js +1608 -559
- package/lib/server.js +41 -5
- package/lib/vad/manifest.json +2 -2
- package/lib/vad/vad.worker.js +1 -1
- package/package.json +2 -2
- package/src/app/client/apply.tsx +176 -50
- package/src/app/client/i18n/catalogs/base.ts +22 -1
- package/src/app/client/i18n/catalogs/en.ts +30 -8
- package/src/app/client/i18n/catalogs/es.ts +29 -6
- package/src/app/client/i18n/catalogs/fr.ts +29 -6
- package/src/app/client/i18n/catalogs/hi.ts +30 -8
- package/src/app/client/i18n/catalogs/pt-BR.ts +30 -8
- package/src/app/client/i18n/catalogs/zh.ts +30 -8
- package/src/app/server/registerRoutes.ts +2 -1
- package/src/modules/conversation/components/ConversationControls.tsx +3 -17
- package/src/modules/conversation/components/createConversationComponents.tsx +2 -16
- package/src/modules/conversation/models/meeting.ts +76 -20
- package/src/modules/conversation/models/meetingTranscript.ts +10 -2
- package/src/modules/core/ARCHITECTURE.md +1 -1
- package/src/modules/core/coordinator.ts +144 -15
- package/src/modules/core/engineSelection.ts +10 -0
- package/src/modules/core/qwen/QwenSettings.tsx +0 -1
- package/src/modules/core/settings.ts +38 -1
- package/src/modules/recognition/ARCHITECTURE.md +2 -0
- package/src/modules/recognition/engines/browser/BrowserRecognitionEngine.ts +57 -5
- package/src/modules/recognition/engines/browser/externalAudioSupport.ts +71 -0
- package/src/modules/recognition/engines/whisper/WhisperSettings.tsx +0 -1
- package/src/modules/settings/ARCHITECTURE.md +4 -0
- package/src/modules/settings/components/LiveVoiceSettings.tsx +62 -24
- package/src/modules/settings/models/browserVoiceSelection.ts +76 -0
- package/src/modules/settings/models/settingsHost.ts +6 -2
- package/src/modules/settings/models/settingsStorage.ts +3 -0
- package/src/modules/settings/sections/conversation/ConversationDelaySettings.tsx +1 -1
- package/src/modules/settings/sections/conversation/ConversationSettingsSection.tsx +12 -10
- package/src/modules/settings/sections/conversation/DeliverySettings.tsx +2 -6
- package/src/modules/settings/sections/conversation/HoldToTalkSettings.tsx +1 -1
- package/src/modules/settings/sections/conversation/MeetingSourceSettings.tsx +30 -0
- package/src/modules/settings/sections/conversation/VoiceModeSettings.tsx +5 -5
- package/src/modules/settings/sections/recognition/RecognitionEngineSettings.tsx +12 -18
- package/src/modules/settings/sections/recognition/RecognitionFilterSettings.tsx +4 -4
- package/src/modules/settings/sections/recognition/RecognitionSettingsSection.tsx +6 -4
- package/src/modules/settings/sections/recognition/SilenceDetectionSettings.tsx +9 -4
- package/src/modules/settings/sections/recognition/VoiceCommandSettings.tsx +13 -12
- package/src/modules/settings/sections/speak/OutputFilterSettings.tsx +7 -3
- package/src/modules/settings/sections/speak/PlaybackPolicySettings.tsx +6 -6
- package/src/modules/settings/sections/speak/SpeakSettingsSection.tsx +5 -3
- package/src/modules/settings/sections/speak/SpeechAdvancedSettings.tsx +1 -1
- package/src/modules/settings/sections/speak/SpeechEngineSettings.tsx +76 -45
- package/src/modules/speak/ARCHITECTURE.md +4 -0
- package/src/modules/speak/engines/audio/HostAudioEngine.ts +26 -8
- package/src/modules/speak/engines/browser/BrowserSpeakingEngine.ts +75 -13
- package/src/modules/speak/services/sessionSpeechMemory.ts +55 -0
- package/src/shared/ARCHITECTURE.md +1 -1
- package/src/shared/design-system/feedback/Hint.tsx +109 -0
- package/src/shared/design-system/forms/CheckboxField.tsx +9 -3
- package/src/shared/design-system/forms/PhraseField.tsx +107 -0
- package/src/shared/design-system/forms/SelectField.tsx +32 -11
- package/src/shared/design-system/icons/icons.ts +5 -0
- package/src/shared/design-system/index.ts +1 -0
- package/src/shared/design-system/layout/SettingsSection.tsx +45 -5
- package/src/shared/design-system/layout/SettingsSectionBody.tsx +6 -0
- package/src/shared/design-system/layout/index.ts +1 -0
- package/src/styles/index.ts +41 -1
package/lib/client.js
CHANGED
|
@@ -34,10 +34,62 @@ __export(apply_exports, {
|
|
|
34
34
|
inject: () => inject
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(apply_exports);
|
|
37
|
-
var
|
|
37
|
+
var import_react64 = __toESM(require("react"), 1);
|
|
38
|
+
|
|
39
|
+
// src/modules/speak/services/sessionSpeechMemory.ts
|
|
40
|
+
var SessionSpeechMemory = class {
|
|
41
|
+
constructor() {
|
|
42
|
+
this.sessions = /* @__PURE__ */ new Map();
|
|
43
|
+
}
|
|
44
|
+
session(key, startedAt = Date.now()) {
|
|
45
|
+
if (!this.sessions.has(key))
|
|
46
|
+
this.sessions.set(key, {
|
|
47
|
+
startedAt,
|
|
48
|
+
observed: /* @__PURE__ */ new Set(),
|
|
49
|
+
textById: /* @__PURE__ */ new Map(),
|
|
50
|
+
frontier: null,
|
|
51
|
+
baselined: false,
|
|
52
|
+
checkpoint: null
|
|
53
|
+
});
|
|
54
|
+
return this.sessions.get(key);
|
|
55
|
+
}
|
|
56
|
+
baseline(state, message2, initial = false) {
|
|
57
|
+
const known = state.observed.has(message2.id);
|
|
58
|
+
const previous = state.frontier;
|
|
59
|
+
const position = [message2.turn, message2.step];
|
|
60
|
+
if (!position.every(Number.isFinite)) return true;
|
|
61
|
+
const newer = !previous || position[0] > previous[0] || position[0] === previous[0] && position[1] > previous[1];
|
|
62
|
+
state.observed.add(message2.id);
|
|
63
|
+
if (newer) state.frontier = position;
|
|
64
|
+
if (known) return false;
|
|
65
|
+
if (Number.isFinite(message2.time)) return message2.time < state.startedAt;
|
|
66
|
+
return initial || !state.baselined || !newer;
|
|
67
|
+
}
|
|
68
|
+
reset(startedAt = Date.now()) {
|
|
69
|
+
for (const state of this.sessions.values()) {
|
|
70
|
+
const old = state.checkpoint;
|
|
71
|
+
const suppressed = /* @__PURE__ */ new Set([
|
|
72
|
+
...old?.suppressed || [],
|
|
73
|
+
...old?.unfinished || [],
|
|
74
|
+
...(old?.pending || []).map((item) => item.id)
|
|
75
|
+
]);
|
|
76
|
+
state.startedAt = startedAt;
|
|
77
|
+
state.checkpoint = {
|
|
78
|
+
consumed: old?.consumed || [],
|
|
79
|
+
unfinished: [],
|
|
80
|
+
suppressed: [...suppressed],
|
|
81
|
+
pending: [],
|
|
82
|
+
paused: false
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
clear() {
|
|
87
|
+
this.sessions.clear();
|
|
88
|
+
}
|
|
89
|
+
};
|
|
38
90
|
|
|
39
91
|
// src/modules/recognition/vad/assets.ts
|
|
40
|
-
var sileroVadAssetBase = () => "/api/dsh-live-voice/vad/" + encodeURIComponent(true ? "0.5.
|
|
92
|
+
var sileroVadAssetBase = () => "/api/dsh-live-voice/vad/" + encodeURIComponent(true ? "0.5.2" : "test") + "/";
|
|
41
93
|
async function sileroVadAvailable(fetchImpl = globalThis.fetch) {
|
|
42
94
|
try {
|
|
43
95
|
const response = await fetchImpl(sileroVadAssetBase() + "availability", {
|
|
@@ -369,7 +421,7 @@ function createVadAssetDiagnostics(base, fetchImpl = globalThis.fetch) {
|
|
|
369
421
|
}
|
|
370
422
|
|
|
371
423
|
// src/modules/conversation/components/SpeechStatusBar.tsx
|
|
372
|
-
var
|
|
424
|
+
var import_react26 = __toESM(require("react"), 1);
|
|
373
425
|
|
|
374
426
|
// src/app/client/i18n/catalogs/en.ts
|
|
375
427
|
var en = {
|
|
@@ -430,9 +482,10 @@ var en = {
|
|
|
430
482
|
"dsh-live-voice.commons.version.label": "DSH Live Voice v{version}",
|
|
431
483
|
"dsh-live-voice.commons.version.link": "DSH Live Voice v{version}. Open releases",
|
|
432
484
|
"dsh-live-voice.commons.version.title": "Version information",
|
|
485
|
+
"dsh-live-voice.meeting.browserLocalUnavailable": "Local browser recognition is unavailable for this language. Install its language pack or explicitly turn off local-only processing in Settings to permit browser-service recognition.",
|
|
486
|
+
"dsh-live-voice.meeting.browserSharedUnsupported": "This browser cannot safely recognize shared audio. Choose Qwen or Whisper HTTP for shared audio.",
|
|
433
487
|
"dsh-live-voice.meeting.failed": "Recognition failed.",
|
|
434
488
|
"dsh-live-voice.meeting.help": "Independent sources; transcripts stay in the composer until you send them manually.",
|
|
435
|
-
"dsh-live-voice.meeting.httpRequired": "Use Qwen or Whisper HTTP for meeting mode.",
|
|
436
489
|
"dsh-live-voice.meeting.inactive": "Inactive",
|
|
437
490
|
"dsh-live-voice.meeting.listening": "Listening",
|
|
438
491
|
"dsh-live-voice.meeting.microphone": "Microphone",
|
|
@@ -455,10 +508,13 @@ var en = {
|
|
|
455
508
|
"dsh-live-voice.recognition.browser.localProcessing": "Process recognition locally on this device",
|
|
456
509
|
"dsh-live-voice.recognition.browser.microphoneHelp": "Browser SpeechRecognition may use the browser or system default microphone instead of this selection.",
|
|
457
510
|
"dsh-live-voice.recognition.browser.remoteServiceWarning": "Browser-service recognition is enabled. The browser may send microphone audio to its recognition service.",
|
|
511
|
+
"dsh-live-voice.recognition.commands.addPhrase": "Add phrase\u2026",
|
|
458
512
|
"dsh-live-voice.recognition.commands.clear": "Clear composer",
|
|
459
513
|
"dsh-live-voice.recognition.commands.enabled": "Enable exact voice commands",
|
|
514
|
+
"dsh-live-voice.recognition.commands.end": "End conversation",
|
|
460
515
|
"dsh-live-voice.recognition.commands.mute": "Mute composer input",
|
|
461
516
|
"dsh-live-voice.recognition.commands.queue": "Put in queue",
|
|
517
|
+
"dsh-live-voice.recognition.commands.removePhrase": "Remove phrase",
|
|
462
518
|
"dsh-live-voice.recognition.commands.resume": "Resume composer input",
|
|
463
519
|
"dsh-live-voice.recognition.commands.send": "Send to running agent",
|
|
464
520
|
"dsh-live-voice.recognition.commands.stopSpeech": "Stop assistant speech",
|
|
@@ -471,6 +527,9 @@ var en = {
|
|
|
471
527
|
"dsh-live-voice.recognition.holdToTalk.help": "While a composer is open, hold Control anywhere on the page to capture speech. Release it to flush queued transcription, wait the configured send delay, queue the message, and close voice capture. Press Escape while holding to cancel.",
|
|
472
528
|
"dsh-live-voice.recognition.language.automatic": "Automatic \u2014 detect language",
|
|
473
529
|
"dsh-live-voice.recognition.language.label": "Recognition language",
|
|
530
|
+
"dsh-live-voice.recognition.language.options.chinese": "Chinese (Mandarin)",
|
|
531
|
+
"dsh-live-voice.recognition.language.options.french": "French",
|
|
532
|
+
"dsh-live-voice.recognition.language.options.spanish": "Spanish",
|
|
474
533
|
"dsh-live-voice.recognition.manualSend.help": "Recognized text stays in the composer until you use the normal DSH Send control.",
|
|
475
534
|
"dsh-live-voice.recognition.maxUtterance.help": "If speech never pauses, start a new transcription chunk after this duration. Default: 60 seconds.",
|
|
476
535
|
"dsh-live-voice.recognition.maxUtterance.label": "Maximum continuous speech (seconds)",
|
|
@@ -556,8 +615,19 @@ var en = {
|
|
|
556
615
|
"dsh-live-voice.settings.engine.refresh": "Refresh available engines",
|
|
557
616
|
"dsh-live-voice.settings.filters.title": "Filtering",
|
|
558
617
|
"dsh-live-voice.settings.general.title": "General",
|
|
618
|
+
"dsh-live-voice.settings.layout.delivery": "Message delivery",
|
|
619
|
+
"dsh-live-voice.settings.layout.diagnostics": "Diagnostics",
|
|
620
|
+
"dsh-live-voice.settings.layout.listening": "Listening & interruptions",
|
|
621
|
+
"dsh-live-voice.settings.layout.playback": "Playback & output",
|
|
622
|
+
"dsh-live-voice.settings.layout.shortcut": "Shortcuts",
|
|
623
|
+
"dsh-live-voice.settings.layout.transcription": "Transcription",
|
|
624
|
+
"dsh-live-voice.settings.layout.voice": "Voice & engine",
|
|
559
625
|
"dsh-live-voice.settings.persistence.loadError": "Could not load Live Voice settings from the server. Reload to try again.",
|
|
560
626
|
"dsh-live-voice.settings.persistence.saveError": "Could not save Live Voice settings on the server. Please try again.",
|
|
627
|
+
"dsh-live-voice.settings.sourceNames.help": "When both sources capture, these names label new transcript blocks, not individual participants. Saved on blur; blank restores Me / Them. Maximum 80 characters. Existing text is unchanged.",
|
|
628
|
+
"dsh-live-voice.settings.sourceNames.microphone": "Microphone source name",
|
|
629
|
+
"dsh-live-voice.settings.sourceNames.shared": "Shared-audio source name",
|
|
630
|
+
"dsh-live-voice.settings.sourceNames.title": "Meeting source names",
|
|
561
631
|
"dsh-live-voice.settings.tabs.conversation": "Conversation",
|
|
562
632
|
"dsh-live-voice.settings.tabs.recognition": "Speech recognition",
|
|
563
633
|
"dsh-live-voice.settings.tabs.speak": "Speech",
|
|
@@ -571,12 +641,13 @@ var en = {
|
|
|
571
641
|
"dsh-live-voice.speak.autoPlayback.disable": "Disable automatic assistant speech",
|
|
572
642
|
"dsh-live-voice.speak.autoPlayback.enable": "Enable automatic assistant speech",
|
|
573
643
|
"dsh-live-voice.speak.autoPlayback.enabled": "Automatically speak new assistant messages",
|
|
574
|
-
"dsh-live-voice.speak.autoPlayback.help": "
|
|
644
|
+
"dsh-live-voice.speak.autoPlayback.help": "New assistant messages are spoken automatically, even with the microphone off. Playback waits while you are speaking.",
|
|
575
645
|
"dsh-live-voice.speak.autoPlayback.label": "Automatic assistant speech",
|
|
576
646
|
"dsh-live-voice.speak.autoPlayback.remainingOne": "Automatic assistant speech: {state} \u2014 {count} speech segment remaining",
|
|
577
647
|
"dsh-live-voice.speak.autoPlayback.remainingOther": "Automatic assistant speech: {state} \u2014 {count} speech segments remaining",
|
|
578
648
|
"dsh-live-voice.speak.autoPlayback.status": "Automatic assistant speech: {state}",
|
|
579
649
|
"dsh-live-voice.speak.browser.automaticVoice": "Automatic local voice",
|
|
650
|
+
"dsh-live-voice.speak.browser.defaultVoice": "default",
|
|
580
651
|
"dsh-live-voice.speak.browser.label": "Browser speech \u2014 device audio",
|
|
581
652
|
"dsh-live-voice.speak.browser.name": "Browser speech",
|
|
582
653
|
"dsh-live-voice.speak.browser.outputHelp": "Browser speech synthesis may ignore the selected output device; this browser API normally follows the system default.",
|
|
@@ -644,7 +715,9 @@ var en = {
|
|
|
644
715
|
"dsh-live-voice.speak.segmentGap.help": "Wait this many milliseconds between consecutive spoken segments. 400 ms is the default.",
|
|
645
716
|
"dsh-live-voice.speak.segmentGap.label": "Pause between speech segments",
|
|
646
717
|
"dsh-live-voice.speak.status.paused": "Speech paused",
|
|
647
|
-
"dsh-live-voice.speak.status.playing": "Speaking"
|
|
718
|
+
"dsh-live-voice.speak.status.playing": "Speaking",
|
|
719
|
+
"dsh-live-voice.speak.volume.help": "Speech playback only: 0% is silent; 100% is full volume (default). Microphone input is unchanged. Browser speech changes apply from the next segment.",
|
|
720
|
+
"dsh-live-voice.speak.volume.label": "Speech volume"
|
|
648
721
|
};
|
|
649
722
|
var en_default = Object.freeze(en);
|
|
650
723
|
|
|
@@ -707,9 +780,10 @@ var es = {
|
|
|
707
780
|
"dsh-live-voice.commons.version.label": "DSH Voz en vivo v{version}",
|
|
708
781
|
"dsh-live-voice.commons.version.link": "DSH Voz en vivo v{version}. Abrir la lista de versiones",
|
|
709
782
|
"dsh-live-voice.commons.version.title": "Informaci\xF3n de versi\xF3n",
|
|
783
|
+
"dsh-live-voice.meeting.browserLocalUnavailable": "El reconocimiento local del navegador no est\xE1 disponible para este idioma. Instala su paquete de idioma o desactiva expl\xEDcitamente el procesamiento solo local en Ajustes para permitir el servicio del navegador.",
|
|
784
|
+
"dsh-live-voice.meeting.browserSharedUnsupported": "Este navegador no puede reconocer audio compartido de forma segura. Elige Qwen o Whisper HTTP para el audio compartido.",
|
|
710
785
|
"dsh-live-voice.meeting.failed": "Error de reconocimiento.",
|
|
711
786
|
"dsh-live-voice.meeting.help": "Fuentes independientes; env\xEDa las transcripciones manualmente desde el editor.",
|
|
712
|
-
"dsh-live-voice.meeting.httpRequired": "Usa Qwen o Whisper HTTP para el modo reuni\xF3n.",
|
|
713
787
|
"dsh-live-voice.meeting.inactive": "Inactivo",
|
|
714
788
|
"dsh-live-voice.meeting.listening": "Escuchando",
|
|
715
789
|
"dsh-live-voice.meeting.microphone": "Micr\xF3fono",
|
|
@@ -732,10 +806,13 @@ var es = {
|
|
|
732
806
|
"dsh-live-voice.recognition.browser.localProcessing": "Procesar el reconocimiento localmente en este dispositivo",
|
|
733
807
|
"dsh-live-voice.recognition.browser.microphoneHelp": "SpeechRecognition puede utilizar el micr\xF3fono predeterminado del navegador o del sistema en lugar del seleccionado aqu\xED.",
|
|
734
808
|
"dsh-live-voice.recognition.browser.remoteServiceWarning": "El reconocimiento mediante el servicio del navegador est\xE1 activado. El navegador puede enviar el audio del micr\xF3fono a su servicio de reconocimiento.",
|
|
809
|
+
"dsh-live-voice.recognition.commands.addPhrase": "A\xF1adir frase\u2026",
|
|
735
810
|
"dsh-live-voice.recognition.commands.clear": "Vaciar el cuadro de mensaje",
|
|
736
811
|
"dsh-live-voice.recognition.commands.enabled": "Activar comandos de voz con coincidencia exacta",
|
|
812
|
+
"dsh-live-voice.recognition.commands.end": "Finalizar conversaci\xF3n",
|
|
737
813
|
"dsh-live-voice.recognition.commands.mute": "Suspender la entrada de voz en el cuadro de mensaje",
|
|
738
814
|
"dsh-live-voice.recognition.commands.queue": "A\xF1adir a la cola",
|
|
815
|
+
"dsh-live-voice.recognition.commands.removePhrase": "Eliminar frase",
|
|
739
816
|
"dsh-live-voice.recognition.commands.resume": "Reanudar la entrada de voz en el cuadro de mensaje",
|
|
740
817
|
"dsh-live-voice.recognition.commands.send": "Enviar al agente en ejecuci\xF3n",
|
|
741
818
|
"dsh-live-voice.recognition.commands.stopSpeech": "Detener la lectura en voz alta del asistente",
|
|
@@ -748,6 +825,9 @@ var es = {
|
|
|
748
825
|
"dsh-live-voice.recognition.holdToTalk.help": "Con un cuadro de mensaje abierto, mant\xE9n Control pulsado en cualquier parte de la p\xE1gina para capturar tu voz. Al soltarlo, se procesa la transcripci\xF3n pendiente, se espera el retraso de env\xEDo configurado, se a\xF1ade el mensaje a la cola y se cierra la captura de voz. Pulsa Escape mientras mantienes Control para cancelar.",
|
|
749
826
|
"dsh-live-voice.recognition.language.automatic": "Autom\xE1tico \u2014 detectar idioma",
|
|
750
827
|
"dsh-live-voice.recognition.language.label": "Idioma de reconocimiento",
|
|
828
|
+
"dsh-live-voice.recognition.language.options.chinese": "Chino (mandar\xEDn)",
|
|
829
|
+
"dsh-live-voice.recognition.language.options.french": "Franc\xE9s",
|
|
830
|
+
"dsh-live-voice.recognition.language.options.spanish": "Espa\xF1ol",
|
|
751
831
|
"dsh-live-voice.recognition.manualSend.help": "El texto reconocido permanece en el cuadro de mensaje hasta que utilices el bot\xF3n de env\xEDo habitual de DSH.",
|
|
752
832
|
"dsh-live-voice.recognition.maxUtterance.help": "Si hablas sin hacer pausas, se inicia un nuevo fragmento de transcripci\xF3n tras este intervalo. Valor predeterminado: 60 segundos.",
|
|
753
833
|
"dsh-live-voice.recognition.maxUtterance.label": "Duraci\xF3n m\xE1xima del habla continua (segundos)",
|
|
@@ -833,8 +913,19 @@ var es = {
|
|
|
833
913
|
"dsh-live-voice.settings.engine.refresh": "Actualizar los motores disponibles",
|
|
834
914
|
"dsh-live-voice.settings.filters.title": "Filtrado",
|
|
835
915
|
"dsh-live-voice.settings.general.title": "General",
|
|
916
|
+
"dsh-live-voice.settings.layout.delivery": "Env\xEDo de mensajes",
|
|
917
|
+
"dsh-live-voice.settings.layout.diagnostics": "Diagn\xF3stico",
|
|
918
|
+
"dsh-live-voice.settings.layout.listening": "Escucha e interrupciones",
|
|
919
|
+
"dsh-live-voice.settings.layout.playback": "Reproducci\xF3n y salida",
|
|
920
|
+
"dsh-live-voice.settings.layout.shortcut": "Atajos",
|
|
921
|
+
"dsh-live-voice.settings.layout.transcription": "Transcripci\xF3n",
|
|
922
|
+
"dsh-live-voice.settings.layout.voice": "Voz y motor",
|
|
836
923
|
"dsh-live-voice.settings.persistence.loadError": "No se pudieron cargar los ajustes de Voz en vivo del servidor. Recarga para volver a intentarlo.",
|
|
837
924
|
"dsh-live-voice.settings.persistence.saveError": "No se pudieron guardar los ajustes de Voz en vivo en el servidor. Int\xE9ntalo de nuevo.",
|
|
925
|
+
"dsh-live-voice.settings.sourceNames.help": "Cuando ambas fuentes capturan, estos nombres etiquetan nuevos bloques de transcripci\xF3n, no participantes individuales. Se guardan al salir del campo; vac\xEDo restaura Me / Them. M\xE1ximo 80 caracteres. El texto existente no cambia.",
|
|
926
|
+
"dsh-live-voice.settings.sourceNames.microphone": "Nombre de la fuente del micr\xF3fono",
|
|
927
|
+
"dsh-live-voice.settings.sourceNames.shared": "Nombre de la fuente del audio compartido",
|
|
928
|
+
"dsh-live-voice.settings.sourceNames.title": "Nombres de fuentes de la reuni\xF3n",
|
|
838
929
|
"dsh-live-voice.settings.tabs.conversation": "Conversaci\xF3n",
|
|
839
930
|
"dsh-live-voice.settings.tabs.recognition": "Reconocimiento de voz",
|
|
840
931
|
"dsh-live-voice.settings.tabs.speak": "S\xEDntesis de voz",
|
|
@@ -848,12 +939,13 @@ var es = {
|
|
|
848
939
|
"dsh-live-voice.speak.autoPlayback.disable": "Desactivar voz autom\xE1tica del asistente",
|
|
849
940
|
"dsh-live-voice.speak.autoPlayback.enable": "Activar voz autom\xE1tica del asistente",
|
|
850
941
|
"dsh-live-voice.speak.autoPlayback.enabled": "Leer autom\xE1ticamente los nuevos mensajes del asistente en voz alta",
|
|
851
|
-
"dsh-live-voice.speak.autoPlayback.help": "
|
|
942
|
+
"dsh-live-voice.speak.autoPlayback.help": "Los nuevos mensajes del asistente se leen autom\xE1ticamente, incluso con el micr\xF3fono apagado. La reproducci\xF3n espera mientras hablas.",
|
|
852
943
|
"dsh-live-voice.speak.autoPlayback.label": "Lectura autom\xE1tica del asistente",
|
|
853
944
|
"dsh-live-voice.speak.autoPlayback.remainingOne": "Lectura autom\xE1tica del asistente: {state} \u2014 queda {count} segmento de voz",
|
|
854
945
|
"dsh-live-voice.speak.autoPlayback.remainingOther": "Lectura autom\xE1tica del asistente: {state} \u2014 quedan {count} segmentos de voz",
|
|
855
946
|
"dsh-live-voice.speak.autoPlayback.status": "Lectura autom\xE1tica del asistente: {state}",
|
|
856
947
|
"dsh-live-voice.speak.browser.automaticVoice": "Voz local autom\xE1tica",
|
|
948
|
+
"dsh-live-voice.speak.browser.defaultVoice": "predeterminada",
|
|
857
949
|
"dsh-live-voice.speak.browser.label": "S\xEDntesis de voz del navegador \u2014 audio en este dispositivo",
|
|
858
950
|
"dsh-live-voice.speak.browser.name": "S\xEDntesis de voz del navegador",
|
|
859
951
|
"dsh-live-voice.speak.browser.outputHelp": "La s\xEDntesis de voz del navegador puede ignorar el dispositivo de salida seleccionado; esta API del navegador normalmente utiliza el predeterminado del sistema.",
|
|
@@ -921,7 +1013,9 @@ var es = {
|
|
|
921
1013
|
"dsh-live-voice.speak.segmentGap.help": "Espera esta cantidad de milisegundos entre segmentos hablados consecutivos. El valor predeterminado es 400 ms.",
|
|
922
1014
|
"dsh-live-voice.speak.segmentGap.label": "Pausa entre segmentos de voz",
|
|
923
1015
|
"dsh-live-voice.speak.status.paused": "Lectura en pausa",
|
|
924
|
-
"dsh-live-voice.speak.status.playing": "Hablando"
|
|
1016
|
+
"dsh-live-voice.speak.status.playing": "Hablando",
|
|
1017
|
+
"dsh-live-voice.speak.volume.help": "Solo reproducci\xF3n de voz: 0% es silencio; 100% es el volumen m\xE1ximo (predeterminado). El micr\xF3fono no cambia. En Browser, los cambios se aplican desde el siguiente segmento.",
|
|
1018
|
+
"dsh-live-voice.speak.volume.label": "Volumen de voz"
|
|
925
1019
|
};
|
|
926
1020
|
var es_default = Object.freeze(es);
|
|
927
1021
|
|
|
@@ -984,9 +1078,10 @@ var fr = {
|
|
|
984
1078
|
"dsh-live-voice.commons.version.label": "DSH Voix en direct v{version}",
|
|
985
1079
|
"dsh-live-voice.commons.version.link": "DSH Voix en direct v{version}. Ouvrir la liste des versions",
|
|
986
1080
|
"dsh-live-voice.commons.version.title": "Informations de version",
|
|
1081
|
+
"dsh-live-voice.meeting.browserLocalUnavailable": "La reconnaissance locale du navigateur est indisponible pour cette langue. Installez son pack linguistique ou d\xE9sactivez explicitement le traitement uniquement local dans les param\xE8tres pour autoriser le service du navigateur.",
|
|
1082
|
+
"dsh-live-voice.meeting.browserSharedUnsupported": "Ce navigateur ne peut pas reconna\xEEtre l\u2019audio partag\xE9 en toute s\xE9curit\xE9. Choisissez Qwen ou Whisper HTTP pour l\u2019audio partag\xE9.",
|
|
987
1083
|
"dsh-live-voice.meeting.failed": "\xC9chec de reconnaissance.",
|
|
988
1084
|
"dsh-live-voice.meeting.help": "Sources ind\xE9pendantes ; envoyez les transcriptions manuellement depuis l\u2019\xE9diteur.",
|
|
989
|
-
"dsh-live-voice.meeting.httpRequired": "Utilisez Qwen ou Whisper HTTP en mode r\xE9union.",
|
|
990
1085
|
"dsh-live-voice.meeting.inactive": "Inactif",
|
|
991
1086
|
"dsh-live-voice.meeting.listening": "\xC9coute",
|
|
992
1087
|
"dsh-live-voice.meeting.microphone": "Microphone",
|
|
@@ -1009,10 +1104,13 @@ var fr = {
|
|
|
1009
1104
|
"dsh-live-voice.recognition.browser.localProcessing": "Effectuer la reconnaissance localement sur cet appareil",
|
|
1010
1105
|
"dsh-live-voice.recognition.browser.microphoneHelp": "SpeechRecognition peut utiliser le microphone par d\xE9faut du navigateur ou du syst\xE8me plut\xF4t que celui s\xE9lectionn\xE9 ici.",
|
|
1011
1106
|
"dsh-live-voice.recognition.browser.remoteServiceWarning": "La reconnaissance via le service du navigateur est activ\xE9e. Le navigateur peut envoyer le son du microphone \xE0 son service de reconnaissance.",
|
|
1107
|
+
"dsh-live-voice.recognition.commands.addPhrase": "Ajouter une phrase\u2026",
|
|
1012
1108
|
"dsh-live-voice.recognition.commands.clear": "Vider la zone de r\xE9daction",
|
|
1013
1109
|
"dsh-live-voice.recognition.commands.enabled": "Activer les commandes vocales par correspondance exacte",
|
|
1110
|
+
"dsh-live-voice.recognition.commands.end": "Terminer la conversation",
|
|
1014
1111
|
"dsh-live-voice.recognition.commands.mute": "Suspendre la saisie vocale dans la zone de r\xE9daction",
|
|
1015
1112
|
"dsh-live-voice.recognition.commands.queue": "Mettre en file d\u2019attente",
|
|
1113
|
+
"dsh-live-voice.recognition.commands.removePhrase": "Supprimer la phrase",
|
|
1016
1114
|
"dsh-live-voice.recognition.commands.resume": "Reprendre la saisie vocale dans la zone de r\xE9daction",
|
|
1017
1115
|
"dsh-live-voice.recognition.commands.send": "Envoyer \xE0 l\u2019agent en cours d\u2019ex\xE9cution",
|
|
1018
1116
|
"dsh-live-voice.recognition.commands.stopSpeech": "Arr\xEAter la lecture vocale de l\u2019assistant",
|
|
@@ -1025,6 +1123,9 @@ var fr = {
|
|
|
1025
1123
|
"dsh-live-voice.recognition.holdToTalk.help": "Lorsqu\u2019une zone de r\xE9daction est ouverte, maintenez Ctrl n\u2019importe o\xF9 sur la page pour capturer votre voix. Rel\xE2chez la touche pour traiter la transcription en attente, attendre le d\xE9lai d\u2019envoi configur\xE9, mettre le message en file d\u2019attente et arr\xEAter la capture vocale. Appuyez sur \xC9chap tout en maintenant Ctrl pour annuler.",
|
|
1026
1124
|
"dsh-live-voice.recognition.language.automatic": "Automatique \u2014 d\xE9tecter la langue",
|
|
1027
1125
|
"dsh-live-voice.recognition.language.label": "Langue de reconnaissance",
|
|
1126
|
+
"dsh-live-voice.recognition.language.options.chinese": "Chinois (mandarin)",
|
|
1127
|
+
"dsh-live-voice.recognition.language.options.french": "Fran\xE7ais",
|
|
1128
|
+
"dsh-live-voice.recognition.language.options.spanish": "Espagnol",
|
|
1028
1129
|
"dsh-live-voice.recognition.manualSend.help": "Le texte reconnu reste dans la zone de r\xE9daction jusqu\u2019\xE0 ce que vous utilisiez le bouton d\u2019envoi habituel de DSH.",
|
|
1029
1130
|
"dsh-live-voice.recognition.maxUtterance.help": "Si vous parlez sans pause, un nouveau segment de transcription commence apr\xE8s cette dur\xE9e. Valeur par d\xE9faut : 60 secondes.",
|
|
1030
1131
|
"dsh-live-voice.recognition.maxUtterance.label": "Dur\xE9e maximale de parole continue (secondes)",
|
|
@@ -1110,8 +1211,19 @@ var fr = {
|
|
|
1110
1211
|
"dsh-live-voice.settings.engine.refresh": "Actualiser les moteurs disponibles",
|
|
1111
1212
|
"dsh-live-voice.settings.filters.title": "Filtrage",
|
|
1112
1213
|
"dsh-live-voice.settings.general.title": "G\xE9n\xE9ral",
|
|
1214
|
+
"dsh-live-voice.settings.layout.delivery": "Envoi des messages",
|
|
1215
|
+
"dsh-live-voice.settings.layout.diagnostics": "Diagnostic",
|
|
1216
|
+
"dsh-live-voice.settings.layout.listening": "\xC9coute et interruptions",
|
|
1217
|
+
"dsh-live-voice.settings.layout.playback": "Lecture et sortie",
|
|
1218
|
+
"dsh-live-voice.settings.layout.shortcut": "Raccourcis",
|
|
1219
|
+
"dsh-live-voice.settings.layout.transcription": "Transcription vocale",
|
|
1220
|
+
"dsh-live-voice.settings.layout.voice": "Voix et moteur",
|
|
1113
1221
|
"dsh-live-voice.settings.persistence.loadError": "Impossible de charger les param\xE8tres Voix en direct depuis le serveur. Rechargez pour r\xE9essayer.",
|
|
1114
1222
|
"dsh-live-voice.settings.persistence.saveError": "Impossible de sauvegarder les param\xE8tres Voix en direct sur le serveur. R\xE9essayez.",
|
|
1223
|
+
"dsh-live-voice.settings.sourceNames.help": "Lorsque les deux sources capturent, ces noms identifient les nouveaux blocs de transcription, pas les participants individuels. Enregistr\xE9s en quittant le champ ; vide r\xE9tablit Me / Them. Maximum 80 caract\xE8res. Le texte existant reste inchang\xE9.",
|
|
1224
|
+
"dsh-live-voice.settings.sourceNames.microphone": "Nom de la source microphone",
|
|
1225
|
+
"dsh-live-voice.settings.sourceNames.shared": "Nom de la source audio partag\xE9",
|
|
1226
|
+
"dsh-live-voice.settings.sourceNames.title": "Noms des sources de r\xE9union",
|
|
1115
1227
|
"dsh-live-voice.settings.tabs.conversation": "Conversation",
|
|
1116
1228
|
"dsh-live-voice.settings.tabs.recognition": "Reconnaissance vocale",
|
|
1117
1229
|
"dsh-live-voice.settings.tabs.speak": "Synth\xE8se vocale",
|
|
@@ -1125,12 +1237,13 @@ var fr = {
|
|
|
1125
1237
|
"dsh-live-voice.speak.autoPlayback.disable": "D\xE9sactiver la lecture automatique de l\u2019assistant",
|
|
1126
1238
|
"dsh-live-voice.speak.autoPlayback.enable": "Activer la lecture automatique de l\u2019assistant",
|
|
1127
1239
|
"dsh-live-voice.speak.autoPlayback.enabled": "Lire automatiquement les nouveaux messages de l\u2019assistant",
|
|
1128
|
-
"dsh-live-voice.speak.autoPlayback.help": "
|
|
1240
|
+
"dsh-live-voice.speak.autoPlayback.help": "Les nouveaux messages de l\u2019assistant sont lus automatiquement, m\xEAme avec le microphone d\xE9sactiv\xE9. La lecture attend pendant que vous parlez.",
|
|
1129
1241
|
"dsh-live-voice.speak.autoPlayback.label": "Lecture automatique de l\u2019assistant",
|
|
1130
1242
|
"dsh-live-voice.speak.autoPlayback.remainingOne": "Lecture automatique de l\u2019assistant : {state} \u2014 {count} segment vocal restant",
|
|
1131
1243
|
"dsh-live-voice.speak.autoPlayback.remainingOther": "Lecture automatique de l\u2019assistant : {state} \u2014 {count} segments vocaux restants",
|
|
1132
1244
|
"dsh-live-voice.speak.autoPlayback.status": "Lecture automatique de l\u2019assistant : {state}",
|
|
1133
1245
|
"dsh-live-voice.speak.browser.automaticVoice": "Voix locale automatique",
|
|
1246
|
+
"dsh-live-voice.speak.browser.defaultVoice": "par d\xE9faut",
|
|
1134
1247
|
"dsh-live-voice.speak.browser.label": "Synth\xE8se vocale du navigateur \u2014 son sur cet appareil",
|
|
1135
1248
|
"dsh-live-voice.speak.browser.name": "Synth\xE8se vocale du navigateur",
|
|
1136
1249
|
"dsh-live-voice.speak.browser.outputHelp": "La synth\xE8se vocale du navigateur peut ignorer le p\xE9riph\xE9rique de sortie s\xE9lectionn\xE9 ; cette API du navigateur utilise normalement celui d\xE9fini par d\xE9faut sur le syst\xE8me.",
|
|
@@ -1198,7 +1311,9 @@ var fr = {
|
|
|
1198
1311
|
"dsh-live-voice.speak.segmentGap.help": "Attend ce nombre de millisecondes entre des segments vocaux cons\xE9cutifs. La valeur par d\xE9faut est 400 ms.",
|
|
1199
1312
|
"dsh-live-voice.speak.segmentGap.label": "Pause entre les segments vocaux",
|
|
1200
1313
|
"dsh-live-voice.speak.status.paused": "Lecture en pause",
|
|
1201
|
-
"dsh-live-voice.speak.status.playing": "Lecture en cours"
|
|
1314
|
+
"dsh-live-voice.speak.status.playing": "Lecture en cours",
|
|
1315
|
+
"dsh-live-voice.speak.volume.help": "Lecture vocale uniquement : 0% est silencieux ; 100% est le volume maximal (par d\xE9faut). Le microphone reste inchang\xE9. Dans Browser, les changements prennent effet au segment suivant.",
|
|
1316
|
+
"dsh-live-voice.speak.volume.label": "Volume de la voix"
|
|
1202
1317
|
};
|
|
1203
1318
|
var fr_default = Object.freeze(fr);
|
|
1204
1319
|
|
|
@@ -1261,9 +1376,10 @@ var hi = {
|
|
|
1261
1376
|
"dsh-live-voice.commons.version.label": "DSH \u0932\u093E\u0907\u0935 \u0935\u0949\u0907\u0938 v{version}",
|
|
1262
1377
|
"dsh-live-voice.commons.version.link": "DSH \u0932\u093E\u0907\u0935 \u0935\u0949\u0907\u0938 v{version}\u0964 \u0930\u093F\u0932\u0940\u091C\u093C \u0938\u0942\u091A\u0940 \u0916\u094B\u0932\u0947\u0902",
|
|
1263
1378
|
"dsh-live-voice.commons.version.title": "\u0938\u0902\u0938\u094D\u0915\u0930\u0923 \u091C\u093E\u0928\u0915\u093E\u0930\u0940",
|
|
1379
|
+
"dsh-live-voice.meeting.browserLocalUnavailable": "\u0907\u0938 \u092D\u093E\u0937\u093E \u0915\u0947 \u0932\u093F\u090F \u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u0915\u0940 \u0938\u094D\u0925\u093E\u0928\u0940\u092F \u092A\u0939\u091A\u093E\u0928 \u0909\u092A\u0932\u092C\u094D\u0927 \u0928\u0939\u0940\u0902 \u0939\u0948\u0964 \u092D\u093E\u0937\u093E \u092A\u0948\u0915 \u0907\u0902\u0938\u094D\u091F\u0949\u0932 \u0915\u0930\u0947\u0902 \u092F\u093E \u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u0938\u0947\u0935\u093E \u0915\u0940 \u0905\u0928\u0941\u092E\u0924\u093F \u0926\u0947\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u0938\u0947\u091F\u093F\u0902\u0917\u094D\u0938 \u092E\u0947\u0902 \u0915\u0947\u0935\u0932 \u0938\u094D\u0925\u093E\u0928\u0940\u092F \u092A\u094D\u0930\u094B\u0938\u0947\u0938\u093F\u0902\u0917 \u0938\u094D\u092A\u0937\u094D\u091F \u0930\u0942\u092A \u0938\u0947 \u092C\u0902\u0926 \u0915\u0930\u0947\u0902\u0964",
|
|
1380
|
+
"dsh-live-voice.meeting.browserSharedUnsupported": "\u092F\u0939 \u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u0938\u093E\u091D\u093E \u0911\u0921\u093F\u092F\u094B \u0915\u094B \u0938\u0941\u0930\u0915\u094D\u0937\u093F\u0924 \u0930\u0942\u092A \u0938\u0947 \u0928\u0939\u0940\u0902 \u092A\u0939\u091A\u093E\u0928 \u0938\u0915\u0924\u093E\u0964 \u0938\u093E\u091D\u093E \u0911\u0921\u093F\u092F\u094B \u0915\u0947 \u0932\u093F\u090F Qwen \u092F\u093E Whisper HTTP \u091A\u0941\u0928\u0947\u0902\u0964",
|
|
1264
1381
|
"dsh-live-voice.meeting.failed": "\u092A\u0939\u091A\u093E\u0928 \u0935\u093F\u092B\u0932 \u0939\u0941\u0908\u0964",
|
|
1265
1382
|
"dsh-live-voice.meeting.help": "\u0938\u094D\u0935\u0924\u0902\u0924\u094D\u0930 \u0938\u094D\u0930\u094B\u0924; \u0938\u0902\u092A\u093E\u0926\u0915 \u0938\u0947 \u0932\u093F\u092A\u094D\u092F\u0902\u0924\u0930\u0923 \u0938\u094D\u0935\u092F\u0902 \u092D\u0947\u091C\u0947\u0902\u0964",
|
|
1266
|
-
"dsh-live-voice.meeting.httpRequired": "\u092C\u0948\u0920\u0915 \u092E\u094B\u0921 \u0915\u0947 \u0932\u093F\u090F Qwen \u092F\u093E Whisper HTTP \u0909\u092A\u092F\u094B\u0917 \u0915\u0930\u0947\u0902\u0964",
|
|
1267
1383
|
"dsh-live-voice.meeting.inactive": "\u0928\u093F\u0937\u094D\u0915\u094D\u0930\u093F\u092F",
|
|
1268
1384
|
"dsh-live-voice.meeting.listening": "\u0938\u0941\u0928 \u0930\u0939\u093E \u0939\u0948",
|
|
1269
1385
|
"dsh-live-voice.meeting.microphone": "\u092E\u093E\u0907\u0915\u094D\u0930\u094B\u092B\u093C\u094B\u0928",
|
|
@@ -1286,10 +1402,13 @@ var hi = {
|
|
|
1286
1402
|
"dsh-live-voice.recognition.browser.localProcessing": "\u0935\u093E\u0915\u094D \u092A\u0939\u091A\u093E\u0928 \u0915\u0940 \u092A\u094D\u0930\u094B\u0938\u0947\u0938\u093F\u0902\u0917 \u0907\u0938\u0940 \u0921\u093F\u0935\u093E\u0907\u0938 \u092A\u0930 \u0938\u094D\u0925\u093E\u0928\u0940\u092F \u0930\u0942\u092A \u0938\u0947 \u0915\u0930\u0947\u0902",
|
|
1287
1403
|
"dsh-live-voice.recognition.browser.microphoneHelp": "\u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u0915\u093E SpeechRecognition \u092F\u0939\u093E\u0901 \u091A\u0941\u0928\u0947 \u0917\u090F \u092E\u093E\u0907\u0915\u094D\u0930\u094B\u092B\u093C\u094B\u0928 \u0915\u0947 \u092C\u091C\u093E\u092F \u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u092F\u093E \u0938\u093F\u0938\u094D\u091F\u092E \u0915\u0947 \u0921\u093F\u092B\u093C\u0949\u0932\u094D\u091F \u092E\u093E\u0907\u0915\u094D\u0930\u094B\u092B\u093C\u094B\u0928 \u0915\u093E \u0909\u092A\u092F\u094B\u0917 \u0915\u0930 \u0938\u0915\u0924\u093E \u0939\u0948\u0964",
|
|
1288
1404
|
"dsh-live-voice.recognition.browser.remoteServiceWarning": "\u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u0938\u0947\u0935\u093E \u0915\u0947 \u091C\u093C\u0930\u093F\u090F \u0935\u093E\u0915\u094D \u092A\u0939\u091A\u093E\u0928 \u091A\u093E\u0932\u0942 \u0939\u0948\u0964 \u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u092E\u093E\u0907\u0915\u094D\u0930\u094B\u092B\u093C\u094B\u0928 \u0915\u093E \u0911\u0921\u093F\u092F\u094B \u0905\u092A\u0928\u0940 \u0935\u093E\u0915\u094D \u092A\u0939\u091A\u093E\u0928 \u0938\u0947\u0935\u093E \u0915\u094B \u092D\u0947\u091C \u0938\u0915\u0924\u093E \u0939\u0948\u0964",
|
|
1405
|
+
"dsh-live-voice.recognition.commands.addPhrase": "\u0935\u093E\u0915\u094D\u092F\u093E\u0902\u0936 \u091C\u094B\u0921\u093C\u0947\u0902\u2026",
|
|
1289
1406
|
"dsh-live-voice.recognition.commands.clear": "\u0938\u0902\u0926\u0947\u0936 \u0932\u093F\u0916\u0928\u0947 \u0915\u093E \u092C\u0949\u0915\u094D\u0938 \u0916\u093E\u0932\u0940 \u0915\u0930\u0947\u0902",
|
|
1290
1407
|
"dsh-live-voice.recognition.commands.enabled": "\u0939\u0942\u092C\u0939\u0942 \u092E\u093F\u0932\u093E\u0928 \u0935\u093E\u0932\u0947 \u0935\u0949\u0907\u0938 \u0915\u092E\u093E\u0902\u0921 \u091A\u093E\u0932\u0942 \u0915\u0930\u0947\u0902",
|
|
1408
|
+
"dsh-live-voice.recognition.commands.end": "\u092C\u093E\u0924\u091A\u0940\u0924 \u0938\u092E\u093E\u092A\u094D\u0924 \u0915\u0930\u0947\u0902",
|
|
1291
1409
|
"dsh-live-voice.recognition.commands.mute": "\u0938\u0902\u0926\u0947\u0936 \u092C\u0949\u0915\u094D\u0938 \u092E\u0947\u0902 \u0935\u0949\u0907\u0938 \u0907\u0928\u092A\u0941\u091F \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
|
|
1292
1410
|
"dsh-live-voice.recognition.commands.queue": "\u0915\u0924\u093E\u0930 \u092E\u0947\u0902 \u091C\u094B\u0921\u093C\u0947\u0902",
|
|
1411
|
+
"dsh-live-voice.recognition.commands.removePhrase": "\u0935\u093E\u0915\u094D\u092F\u093E\u0902\u0936 \u0939\u091F\u093E\u090F\u0901",
|
|
1293
1412
|
"dsh-live-voice.recognition.commands.resume": "\u0938\u0902\u0926\u0947\u0936 \u092C\u0949\u0915\u094D\u0938 \u092E\u0947\u0902 \u0935\u0949\u0907\u0938 \u0907\u0928\u092A\u0941\u091F \u092B\u093F\u0930 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902",
|
|
1294
1413
|
"dsh-live-voice.recognition.commands.send": "\u091A\u0932 \u0930\u0939\u0947 \u090F\u091C\u0947\u0902\u091F \u0915\u094B \u092D\u0947\u091C\u0947\u0902",
|
|
1295
1414
|
"dsh-live-voice.recognition.commands.stopSpeech": "\u0938\u0939\u093E\u092F\u0915 \u0915\u093E \u0935\u093E\u091A\u0928 \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
|
|
@@ -1302,6 +1421,9 @@ var hi = {
|
|
|
1302
1421
|
"dsh-live-voice.recognition.holdToTalk.help": "\u0938\u0902\u0926\u0947\u0936 \u092C\u0949\u0915\u094D\u0938 \u0916\u0941\u0932\u093E \u0939\u094B\u0928\u0947 \u092A\u0930, \u092A\u0947\u091C \u092A\u0930 \u0915\u0939\u0940\u0902 \u092D\u0940 Control \u0926\u092C\u093E\u090F \u0930\u0916\u0915\u0930 \u0906\u0935\u093E\u091C\u093C \u0930\u093F\u0915\u0949\u0930\u094D\u0921 \u0915\u0930\u0947\u0902\u0964 \u091B\u094B\u0921\u093C\u0928\u0947 \u092A\u0930 \u0915\u0924\u093E\u0930 \u092E\u0947\u0902 \u092E\u094C\u091C\u0942\u0926 \u091F\u094D\u0930\u093E\u0902\u0938\u0915\u094D\u0930\u093F\u092A\u094D\u0936\u0928 \u092A\u0942\u0930\u093E \u0915\u093F\u092F\u093E \u091C\u093E\u0924\u093E \u0939\u0948, \u0924\u092F \u092D\u0947\u091C\u0928\u0947 \u0915\u0947 \u0935\u093F\u0932\u0902\u092C \u0924\u0915 \u092A\u094D\u0930\u0924\u0940\u0915\u094D\u0937\u093E \u0939\u094B\u0924\u0940 \u0939\u0948, \u0938\u0902\u0926\u0947\u0936 \u0915\u0924\u093E\u0930 \u092E\u0947\u0902 \u091C\u0941\u0921\u093C\u0924\u093E \u0939\u0948 \u0914\u0930 \u0906\u0935\u093E\u091C\u093C \u0930\u093F\u0915\u0949\u0930\u094D\u0921 \u0915\u0930\u0928\u093E \u092C\u0902\u0926 \u0939\u094B \u091C\u093E\u0924\u093E \u0939\u0948\u0964 \u0930\u0926\u094D\u0926 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F Control \u0926\u092C\u093E\u090F \u0930\u0916\u0924\u0947 \u0939\u0941\u090F Escape \u0926\u092C\u093E\u090F\u0901\u0964",
|
|
1303
1422
|
"dsh-live-voice.recognition.language.automatic": "\u0938\u094D\u0935\u091A\u093E\u0932\u093F\u0924 \u2014 \u092D\u093E\u0937\u093E \u092A\u0939\u091A\u093E\u0928\u0947\u0902",
|
|
1304
1423
|
"dsh-live-voice.recognition.language.label": "\u0935\u093E\u0915\u094D \u092A\u0939\u091A\u093E\u0928 \u0915\u0940 \u092D\u093E\u0937\u093E",
|
|
1424
|
+
"dsh-live-voice.recognition.language.options.chinese": "\u091A\u0940\u0928\u0940 (\u092E\u0902\u0926\u093E\u0930\u093F\u0928)",
|
|
1425
|
+
"dsh-live-voice.recognition.language.options.french": "\u092B\u093C\u094D\u0930\u0947\u0902\u091A",
|
|
1426
|
+
"dsh-live-voice.recognition.language.options.spanish": "\u0938\u094D\u092A\u0947\u0928\u093F\u0936",
|
|
1305
1427
|
"dsh-live-voice.recognition.manualSend.help": "\u092A\u0939\u091A\u093E\u0928\u093E \u0917\u092F\u093E \u092A\u093E\u0920 \u0938\u0902\u0926\u0947\u0936 \u092C\u0949\u0915\u094D\u0938 \u092E\u0947\u0902 \u0924\u092C \u0924\u0915 \u0930\u0939\u0924\u093E \u0939\u0948 \u091C\u092C \u0924\u0915 \u0906\u092A DSH \u0915\u0947 \u0938\u093E\u092E\u093E\u0928\u094D\u092F \u092D\u0947\u091C\u0947\u0902 \u092C\u091F\u0928 \u0915\u093E \u0909\u092A\u092F\u094B\u0917 \u0928\u0939\u0940\u0902 \u0915\u0930\u0924\u0947\u0964",
|
|
1306
1428
|
"dsh-live-voice.recognition.maxUtterance.help": "\u092F\u0926\u093F \u092C\u094B\u0932\u0928\u093E \u092C\u093F\u0928\u093E \u0930\u0941\u0915\u0947 \u091C\u093E\u0930\u0940 \u0930\u0939\u0947, \u0924\u094B \u0907\u0938 \u0905\u0935\u0927\u093F \u0915\u0947 \u092C\u093E\u0926 \u0928\u092F\u093E \u091F\u094D\u0930\u093E\u0902\u0938\u0915\u094D\u0930\u093F\u092A\u094D\u0936\u0928 \u0916\u0902\u0921 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902\u0964 \u0921\u093F\u092B\u093C\u0949\u0932\u094D\u091F: 60 \u0938\u0947\u0915\u0902\u0921\u0964",
|
|
1307
1429
|
"dsh-live-voice.recognition.maxUtterance.label": "\u0932\u0917\u093E\u0924\u093E\u0930 \u092C\u094B\u0932\u0928\u0947 \u0915\u0940 \u0905\u0927\u093F\u0915\u0924\u092E \u0905\u0935\u0927\u093F (\u0938\u0947\u0915\u0902\u0921)",
|
|
@@ -1387,8 +1509,19 @@ var hi = {
|
|
|
1387
1509
|
"dsh-live-voice.settings.engine.refresh": "\u0909\u092A\u0932\u092C\u094D\u0927 \u0907\u0902\u091C\u0928 \u0930\u0940\u092B\u093C\u094D\u0930\u0947\u0936 \u0915\u0930\u0947\u0902",
|
|
1388
1510
|
"dsh-live-voice.settings.filters.title": "\u092B\u093C\u093F\u0932\u094D\u091F\u0930\u093F\u0902\u0917",
|
|
1389
1511
|
"dsh-live-voice.settings.general.title": "\u0938\u093E\u092E\u093E\u0928\u094D\u092F",
|
|
1512
|
+
"dsh-live-voice.settings.layout.delivery": "\u0938\u0902\u0926\u0947\u0936 \u092D\u0947\u091C\u0928\u093E",
|
|
1513
|
+
"dsh-live-voice.settings.layout.diagnostics": "\u0928\u093F\u0926\u093E\u0928",
|
|
1514
|
+
"dsh-live-voice.settings.layout.listening": "\u0938\u0941\u0928\u0928\u093E \u0914\u0930 \u0935\u094D\u092F\u0935\u0927\u093E\u0928",
|
|
1515
|
+
"dsh-live-voice.settings.layout.playback": "\u092A\u094D\u0932\u0947\u092C\u0948\u0915 \u0914\u0930 \u0906\u0909\u091F\u092A\u0941\u091F",
|
|
1516
|
+
"dsh-live-voice.settings.layout.shortcut": "\u0936\u0949\u0930\u094D\u091F\u0915\u091F",
|
|
1517
|
+
"dsh-live-voice.settings.layout.transcription": "\u091F\u094D\u0930\u093E\u0902\u0938\u0915\u094D\u0930\u093F\u092A\u094D\u0936\u0928",
|
|
1518
|
+
"dsh-live-voice.settings.layout.voice": "\u0906\u0935\u093E\u091C\u093C \u0914\u0930 \u0907\u0902\u091C\u0928",
|
|
1390
1519
|
"dsh-live-voice.settings.persistence.loadError": "\u0938\u0930\u094D\u0935\u0930 \u0938\u0947 \u0932\u093E\u0907\u0935 \u0935\u0949\u0907\u0938 \u0938\u0947\u091F\u093F\u0902\u0917 \u0932\u094B\u0921 \u0928\u0939\u0940\u0902 \u0939\u094B \u0938\u0915\u0940\u0902\u0964 \u092B\u093F\u0930 \u092A\u094D\u0930\u092F\u093E\u0938 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u092A\u0947\u091C \u0930\u0940\u0932\u094B\u0921 \u0915\u0930\u0947\u0902\u0964",
|
|
1391
1520
|
"dsh-live-voice.settings.persistence.saveError": "\u0938\u0930\u094D\u0935\u0930 \u092A\u0930 \u0932\u093E\u0907\u0935 \u0935\u0949\u0907\u0938 \u0938\u0947\u091F\u093F\u0902\u0917 \u0938\u0947\u0935 \u0928\u0939\u0940\u0902 \u0939\u094B \u0938\u0915\u0940\u0902\u0964 \u092B\u093F\u0930 \u092A\u094D\u0930\u092F\u093E\u0938 \u0915\u0930\u0947\u0902\u0964",
|
|
1521
|
+
"dsh-live-voice.settings.sourceNames.help": "\u091C\u092C \u0926\u094B\u0928\u094B\u0902 \u0938\u094D\u0930\u094B\u0924 \u0930\u093F\u0915\u0949\u0930\u094D\u0921 \u0915\u0930\u0924\u0947 \u0939\u0948\u0902, \u092F\u0947 \u0928\u093E\u092E \u0928\u090F \u091F\u094D\u0930\u093E\u0902\u0938\u0915\u094D\u0930\u093F\u092A\u094D\u091F \u092C\u094D\u0932\u0949\u0915 \u0915\u094B \u091A\u093F\u0939\u094D\u0928\u093F\u0924 \u0915\u0930\u0924\u0947 \u0939\u0948\u0902, \u0905\u0932\u0917-\u0905\u0932\u0917 \u092A\u094D\u0930\u0924\u093F\u092D\u093E\u0917\u093F\u092F\u094B\u0902 \u0915\u094B \u0928\u0939\u0940\u0902\u0964 \u092B\u093C\u0940\u0932\u094D\u0921 \u091B\u094B\u0921\u093C\u0928\u0947 \u092A\u0930 \u0938\u0939\u0947\u091C\u0947 \u091C\u093E\u0924\u0947 \u0939\u0948\u0902; \u0916\u093E\u0932\u0940 \u0930\u0916\u0928\u0947 \u092A\u0930 Me / Them \u0935\u093E\u092A\u0938 \u0906\u0924\u0947 \u0939\u0948\u0902\u0964 \u0905\u0927\u093F\u0915\u0924\u092E 80 \u0905\u0915\u094D\u0937\u0930\u0964 \u092E\u094C\u091C\u0942\u0926\u093E \u092A\u093E\u0920 \u0928\u0939\u0940\u0902 \u092C\u0926\u0932\u0924\u093E\u0964",
|
|
1522
|
+
"dsh-live-voice.settings.sourceNames.microphone": "\u092E\u093E\u0907\u0915\u094D\u0930\u094B\u092B\u093C\u094B\u0928 \u0938\u094D\u0930\u094B\u0924 \u0915\u093E \u0928\u093E\u092E",
|
|
1523
|
+
"dsh-live-voice.settings.sourceNames.shared": "\u0938\u093E\u091D\u093E \u0911\u0921\u093F\u092F\u094B \u0938\u094D\u0930\u094B\u0924 \u0915\u093E \u0928\u093E\u092E",
|
|
1524
|
+
"dsh-live-voice.settings.sourceNames.title": "\u092C\u0948\u0920\u0915 \u0938\u094D\u0930\u094B\u0924\u094B\u0902 \u0915\u0947 \u0928\u093E\u092E",
|
|
1392
1525
|
"dsh-live-voice.settings.tabs.conversation": "\u092C\u093E\u0924\u091A\u0940\u0924",
|
|
1393
1526
|
"dsh-live-voice.settings.tabs.recognition": "\u0935\u093E\u0915\u094D \u092A\u0939\u091A\u093E\u0928",
|
|
1394
1527
|
"dsh-live-voice.settings.tabs.speak": "\u0935\u093E\u091A\u0928",
|
|
@@ -1402,12 +1535,13 @@ var hi = {
|
|
|
1402
1535
|
"dsh-live-voice.speak.autoPlayback.disable": "\u0938\u0939\u093E\u092F\u0915 \u0915\u0940 \u0938\u094D\u0935\u091A\u093E\u0932\u093F\u0924 \u0906\u0935\u093E\u091C\u093C \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
|
|
1403
1536
|
"dsh-live-voice.speak.autoPlayback.enable": "\u0938\u0939\u093E\u092F\u0915 \u0915\u0940 \u0938\u094D\u0935\u091A\u093E\u0932\u093F\u0924 \u0906\u0935\u093E\u091C\u093C \u091A\u093E\u0932\u0942 \u0915\u0930\u0947\u0902",
|
|
1404
1537
|
"dsh-live-voice.speak.autoPlayback.enabled": "\u0938\u0939\u093E\u092F\u0915 \u0915\u0947 \u0928\u090F \u0938\u0902\u0926\u0947\u0936 \u0905\u092A\u0928\u0947 \u0906\u092A \u092A\u0922\u093C\u0915\u0930 \u0938\u0941\u0928\u093E\u090F\u0901",
|
|
1405
|
-
"dsh-live-voice.speak.autoPlayback.help": "\
|
|
1538
|
+
"dsh-live-voice.speak.autoPlayback.help": "\u0938\u0939\u093E\u092F\u0915 \u0915\u0947 \u0928\u090F \u0938\u0902\u0926\u0947\u0936 \u0905\u092A\u0928\u0947 \u0906\u092A \u092A\u0922\u093C\u0915\u0930 \u0938\u0941\u0928\u093E\u090F \u091C\u093E\u0924\u0947 \u0939\u0948\u0902, \u092D\u0932\u0947 \u0939\u0940 \u092E\u093E\u0907\u0915\u094D\u0930\u094B\u092B\u093C\u094B\u0928 \u092C\u0902\u0926 \u0939\u094B\u0964 \u091C\u092C \u0906\u092A \u092C\u094B\u0932 \u0930\u0939\u0947 \u0939\u094B\u0902, \u0924\u094B \u092A\u094D\u0932\u0947\u092C\u0948\u0915 \u092A\u094D\u0930\u0924\u0940\u0915\u094D\u0937\u093E \u0915\u0930\u0924\u093E \u0939\u0948\u0964",
|
|
1406
1539
|
"dsh-live-voice.speak.autoPlayback.label": "\u0938\u0939\u093E\u092F\u0915 \u0915\u093E \u0938\u094D\u0935\u091A\u093E\u0932\u093F\u0924 \u0935\u093E\u091A\u0928",
|
|
1407
1540
|
"dsh-live-voice.speak.autoPlayback.remainingOne": "\u0938\u0939\u093E\u092F\u0915 \u0915\u093E \u0938\u094D\u0935\u091A\u093E\u0932\u093F\u0924 \u0935\u093E\u091A\u0928: {state} \u2014 {count} \u0935\u093E\u0915\u094D \u0916\u0902\u0921 \u0936\u0947\u0937 \u0939\u0948",
|
|
1408
1541
|
"dsh-live-voice.speak.autoPlayback.remainingOther": "\u0938\u0939\u093E\u092F\u0915 \u0915\u093E \u0938\u094D\u0935\u091A\u093E\u0932\u093F\u0924 \u0935\u093E\u091A\u0928: {state} \u2014 {count} \u0935\u093E\u0915\u094D \u0916\u0902\u0921 \u0936\u0947\u0937 \u0939\u0948\u0902",
|
|
1409
1542
|
"dsh-live-voice.speak.autoPlayback.status": "\u0938\u0939\u093E\u092F\u0915 \u0915\u093E \u0938\u094D\u0935\u091A\u093E\u0932\u093F\u0924 \u0935\u093E\u091A\u0928: {state}",
|
|
1410
1543
|
"dsh-live-voice.speak.browser.automaticVoice": "\u0938\u094D\u0925\u093E\u0928\u0940\u092F \u0906\u0935\u093E\u091C\u093C \u0915\u093E \u0938\u094D\u0935\u091A\u093E\u0932\u093F\u0924 \u091A\u092F\u0928",
|
|
1544
|
+
"dsh-live-voice.speak.browser.defaultVoice": "\u0921\u093F\u092B\u093C\u0949\u0932\u094D\u091F",
|
|
1411
1545
|
"dsh-live-voice.speak.browser.label": "\u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u0935\u093E\u091A\u0928 \u2014 \u0907\u0938 \u0921\u093F\u0935\u093E\u0907\u0938 \u092A\u0930 \u0911\u0921\u093F\u092F\u094B",
|
|
1412
1546
|
"dsh-live-voice.speak.browser.name": "\u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u0935\u093E\u091A\u0928",
|
|
1413
1547
|
"dsh-live-voice.speak.browser.outputHelp": "\u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u0915\u093E \u0935\u093E\u0915\u094D \u0938\u0902\u0936\u094D\u0932\u0947\u0937\u0923 \u091A\u0941\u0928\u0947 \u0917\u090F \u0906\u0909\u091F\u092A\u0941\u091F \u0921\u093F\u0935\u093E\u0907\u0938 \u0915\u094B \u0905\u0928\u0926\u0947\u0916\u093E \u0915\u0930 \u0938\u0915\u0924\u093E \u0939\u0948; \u092F\u0939 \u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 API \u0938\u093E\u092E\u093E\u0928\u094D\u092F\u0924\u0903 \u0938\u093F\u0938\u094D\u091F\u092E \u0915\u0947 \u0921\u093F\u092B\u093C\u0949\u0932\u094D\u091F \u0915\u093E \u0909\u092A\u092F\u094B\u0917 \u0915\u0930\u0924\u093E \u0939\u0948\u0964",
|
|
@@ -1475,7 +1609,9 @@ var hi = {
|
|
|
1475
1609
|
"dsh-live-voice.speak.segmentGap.help": "\u0932\u0917\u093E\u0924\u093E\u0930 \u092C\u094B\u0932\u0947 \u0917\u090F \u0939\u093F\u0938\u094D\u0938\u094B\u0902 \u0915\u0947 \u092C\u0940\u091A \u0907\u0924\u0928\u0947 \u092E\u093F\u0932\u0940\u0938\u0947\u0915\u0902\u0921 \u0930\u0941\u0915\u0947\u0902\u0964 \u0921\u093F\u092B\u093C\u0949\u0932\u094D\u091F 400 ms \u0939\u0948\u0964",
|
|
1476
1610
|
"dsh-live-voice.speak.segmentGap.label": "\u092C\u094B\u0932\u0947 \u0917\u090F \u0939\u093F\u0938\u094D\u0938\u094B\u0902 \u0915\u0947 \u092C\u0940\u091A \u0935\u093F\u0930\u093E\u092E",
|
|
1477
1611
|
"dsh-live-voice.speak.status.paused": "\u0935\u093E\u091A\u0928 \u0920\u0939\u0930\u093E \u0939\u0941\u0906 \u0939\u0948",
|
|
1478
|
-
"dsh-live-voice.speak.status.playing": "\u092A\u0922\u093C\u0915\u0930 \u0938\u0941\u0928\u093E\u092F\u093E \u091C\u093E \u0930\u0939\u093E \u0939\u0948"
|
|
1612
|
+
"dsh-live-voice.speak.status.playing": "\u092A\u0922\u093C\u0915\u0930 \u0938\u0941\u0928\u093E\u092F\u093E \u091C\u093E \u0930\u0939\u093E \u0939\u0948",
|
|
1613
|
+
"dsh-live-voice.speak.volume.help": "\u0915\u0947\u0935\u0932 \u0935\u093E\u0923\u0940 \u092A\u094D\u0932\u0947\u092C\u0948\u0915: 0% \u092E\u094C\u0928 \u0939\u0948; 100% \u092A\u0942\u0930\u094D\u0923 \u0906\u0935\u093E\u091C\u093C \u0939\u0948 (\u0921\u093F\u092B\u093C\u0949\u0932\u094D\u091F)\u0964 \u092E\u093E\u0907\u0915\u094D\u0930\u094B\u092B\u093C\u094B\u0928 \u0928\u0939\u0940\u0902 \u092C\u0926\u0932\u0924\u093E\u0964 Browser \u092E\u0947\u0902 \u092C\u0926\u0932\u093E\u0935 \u0905\u0917\u0932\u0947 \u0916\u0902\u0921 \u0938\u0947 \u0932\u093E\u0917\u0942 \u0939\u094B\u0924\u0947 \u0939\u0948\u0902\u0964",
|
|
1614
|
+
"dsh-live-voice.speak.volume.label": "\u0935\u093E\u0923\u0940 \u0915\u0940 \u0906\u0935\u093E\u091C\u093C \u0915\u093E \u0938\u094D\u0924\u0930"
|
|
1479
1615
|
};
|
|
1480
1616
|
var hi_default = Object.freeze(hi);
|
|
1481
1617
|
|
|
@@ -1538,9 +1674,10 @@ var ptBR = {
|
|
|
1538
1674
|
"dsh-live-voice.commons.version.label": "DSH Voz ao Vivo v{version}",
|
|
1539
1675
|
"dsh-live-voice.commons.version.link": "DSH Voz ao Vivo v{version}. Abrir vers\xF5es",
|
|
1540
1676
|
"dsh-live-voice.commons.version.title": "Informa\xE7\xF5es da vers\xE3o",
|
|
1677
|
+
"dsh-live-voice.meeting.browserLocalUnavailable": "O reconhecimento local do navegador est\xE1 indispon\xEDvel para este idioma. Instale o pacote de idioma ou desative explicitamente o processamento somente local nas Configura\xE7\xF5es para permitir o servi\xE7o do navegador.",
|
|
1678
|
+
"dsh-live-voice.meeting.browserSharedUnsupported": "Este navegador n\xE3o pode reconhecer \xE1udio compartilhado com seguran\xE7a. Escolha Qwen ou Whisper HTTP para \xE1udio compartilhado.",
|
|
1541
1679
|
"dsh-live-voice.meeting.failed": "Falha no reconhecimento.",
|
|
1542
1680
|
"dsh-live-voice.meeting.help": "Fontes independentes; as transcri\xE7\xF5es ficam no composer at\xE9 voc\xEA envi\xE1-las manualmente.",
|
|
1543
|
-
"dsh-live-voice.meeting.httpRequired": "Use Qwen ou Whisper HTTP no modo reuni\xE3o.",
|
|
1544
1681
|
"dsh-live-voice.meeting.inactive": "Inativo",
|
|
1545
1682
|
"dsh-live-voice.meeting.listening": "Ouvindo",
|
|
1546
1683
|
"dsh-live-voice.meeting.microphone": "Microfone",
|
|
@@ -1563,10 +1700,13 @@ var ptBR = {
|
|
|
1563
1700
|
"dsh-live-voice.recognition.browser.localProcessing": "Processar reconhecimento localmente neste dispositivo",
|
|
1564
1701
|
"dsh-live-voice.recognition.browser.microphoneHelp": "O SpeechRecognition do navegador pode usar o microfone padr\xE3o do sistema ou do navegador em vez desta sele\xE7\xE3o.",
|
|
1565
1702
|
"dsh-live-voice.recognition.browser.remoteServiceWarning": "O reconhecimento pelo servi\xE7o do navegador est\xE1 ativado. O navegador pode enviar o \xE1udio do microfone para o servi\xE7o remoto.",
|
|
1703
|
+
"dsh-live-voice.recognition.commands.addPhrase": "Adicionar frase\u2026",
|
|
1566
1704
|
"dsh-live-voice.recognition.commands.clear": "Limpar editor de mensagens",
|
|
1567
1705
|
"dsh-live-voice.recognition.commands.enabled": "Ativar comandos de voz exatos",
|
|
1706
|
+
"dsh-live-voice.recognition.commands.end": "Encerrar conversa",
|
|
1568
1707
|
"dsh-live-voice.recognition.commands.mute": "Silenciar entrada do editor de mensagens",
|
|
1569
1708
|
"dsh-live-voice.recognition.commands.queue": "Adicionar \xE0 fila",
|
|
1709
|
+
"dsh-live-voice.recognition.commands.removePhrase": "Remover frase",
|
|
1570
1710
|
"dsh-live-voice.recognition.commands.resume": "Retomar entrada do editor de mensagens",
|
|
1571
1711
|
"dsh-live-voice.recognition.commands.send": "Enviar ao agente em execu\xE7\xE3o",
|
|
1572
1712
|
"dsh-live-voice.recognition.commands.stopSpeech": "Parar fala do assistente",
|
|
@@ -1579,6 +1719,9 @@ var ptBR = {
|
|
|
1579
1719
|
"dsh-live-voice.recognition.holdToTalk.help": "Com o editor aberto, segure Control em qualquer lugar da p\xE1gina para capturar a fala. Solte para concluir as transcri\xE7\xF5es pendentes, aguardar o atraso configurado, enfileirar a mensagem e encerrar a captura. Pressione Escape enquanto segura para cancelar.",
|
|
1580
1720
|
"dsh-live-voice.recognition.language.automatic": "Autom\xE1tico \u2014 detectar idioma",
|
|
1581
1721
|
"dsh-live-voice.recognition.language.label": "Idioma de reconhecimento",
|
|
1722
|
+
"dsh-live-voice.recognition.language.options.chinese": "Chin\xEAs (mandarim)",
|
|
1723
|
+
"dsh-live-voice.recognition.language.options.french": "Franc\xEAs",
|
|
1724
|
+
"dsh-live-voice.recognition.language.options.spanish": "Espanhol",
|
|
1582
1725
|
"dsh-live-voice.recognition.manualSend.help": "O texto reconhecido permanece no editor at\xE9 que voc\xEA use o bot\xE3o normal de envio do DSH.",
|
|
1583
1726
|
"dsh-live-voice.recognition.maxUtterance.help": "Se a fala nunca pausar, inicia um novo trecho de transcri\xE7\xE3o ap\xF3s esta dura\xE7\xE3o. Padr\xE3o: 60 segundos.",
|
|
1584
1727
|
"dsh-live-voice.recognition.maxUtterance.label": "Fala cont\xEDnua m\xE1xima (segundos)",
|
|
@@ -1664,8 +1807,19 @@ var ptBR = {
|
|
|
1664
1807
|
"dsh-live-voice.settings.engine.refresh": "Atualizar mecanismos dispon\xEDveis",
|
|
1665
1808
|
"dsh-live-voice.settings.filters.title": "Filtragem",
|
|
1666
1809
|
"dsh-live-voice.settings.general.title": "Gerais",
|
|
1810
|
+
"dsh-live-voice.settings.layout.delivery": "Envio de mensagens",
|
|
1811
|
+
"dsh-live-voice.settings.layout.diagnostics": "Diagn\xF3stico",
|
|
1812
|
+
"dsh-live-voice.settings.layout.listening": "Escuta e interrup\xE7\xF5es",
|
|
1813
|
+
"dsh-live-voice.settings.layout.playback": "Reprodu\xE7\xE3o e sa\xEDda",
|
|
1814
|
+
"dsh-live-voice.settings.layout.shortcut": "Atalhos",
|
|
1815
|
+
"dsh-live-voice.settings.layout.transcription": "Transcri\xE7\xE3o",
|
|
1816
|
+
"dsh-live-voice.settings.layout.voice": "Voz e mecanismo",
|
|
1667
1817
|
"dsh-live-voice.settings.persistence.loadError": "N\xE3o foi poss\xEDvel carregar as configura\xE7\xF5es da Voz ao Vivo do servidor. Recarregue para tentar novamente.",
|
|
1668
1818
|
"dsh-live-voice.settings.persistence.saveError": "N\xE3o foi poss\xEDvel salvar as configura\xE7\xF5es da Voz ao Vivo no servidor. Tente novamente.",
|
|
1819
|
+
"dsh-live-voice.settings.sourceNames.help": "Quando as duas fontes capturam, estes nomes identificam novos blocos da transcri\xE7\xE3o, n\xE3o participantes individuais. Salvos ao sair do campo; vazio restaura Me / Them. M\xE1ximo de 80 caracteres. O texto existente n\xE3o muda.",
|
|
1820
|
+
"dsh-live-voice.settings.sourceNames.microphone": "Nome da fonte do microfone",
|
|
1821
|
+
"dsh-live-voice.settings.sourceNames.shared": "Nome da fonte do \xE1udio compartilhado",
|
|
1822
|
+
"dsh-live-voice.settings.sourceNames.title": "Nomes das fontes da reuni\xE3o",
|
|
1669
1823
|
"dsh-live-voice.settings.tabs.conversation": "Conversa",
|
|
1670
1824
|
"dsh-live-voice.settings.tabs.recognition": "Reconhecimento de voz",
|
|
1671
1825
|
"dsh-live-voice.settings.tabs.speak": "Fala",
|
|
@@ -1679,12 +1833,13 @@ var ptBR = {
|
|
|
1679
1833
|
"dsh-live-voice.speak.autoPlayback.disable": "Desativar fala autom\xE1tica da IA",
|
|
1680
1834
|
"dsh-live-voice.speak.autoPlayback.enable": "Ativar fala autom\xE1tica da IA",
|
|
1681
1835
|
"dsh-live-voice.speak.autoPlayback.enabled": "Falar automaticamente novas mensagens do assistente",
|
|
1682
|
-
"dsh-live-voice.speak.autoPlayback.help": "
|
|
1836
|
+
"dsh-live-voice.speak.autoPlayback.help": "Novas mensagens do assistente s\xE3o faladas automaticamente, mesmo com o microfone desligado. A reprodu\xE7\xE3o aguarda enquanto voc\xEA fala.",
|
|
1683
1837
|
"dsh-live-voice.speak.autoPlayback.label": "Fala autom\xE1tica do assistente",
|
|
1684
1838
|
"dsh-live-voice.speak.autoPlayback.remainingOne": "Fala autom\xE1tica do assistente: {state} \u2014 resta {count} segmento de fala",
|
|
1685
1839
|
"dsh-live-voice.speak.autoPlayback.remainingOther": "Fala autom\xE1tica do assistente: {state} \u2014 restam {count} segmentos de fala",
|
|
1686
1840
|
"dsh-live-voice.speak.autoPlayback.status": "Fala autom\xE1tica do assistente: {state}",
|
|
1687
1841
|
"dsh-live-voice.speak.browser.automaticVoice": "Voz local autom\xE1tica",
|
|
1842
|
+
"dsh-live-voice.speak.browser.defaultVoice": "padr\xE3o",
|
|
1688
1843
|
"dsh-live-voice.speak.browser.label": "Fala do navegador \u2014 \xE1udio neste dispositivo",
|
|
1689
1844
|
"dsh-live-voice.speak.browser.name": "Fala do navegador",
|
|
1690
1845
|
"dsh-live-voice.speak.browser.outputHelp": "A s\xEDntese de fala do navegador pode ignorar o dispositivo de sa\xEDda selecionado; esta API normalmente segue o padr\xE3o do sistema.",
|
|
@@ -1752,7 +1907,9 @@ var ptBR = {
|
|
|
1752
1907
|
"dsh-live-voice.speak.segmentGap.help": "Aguarde esta quantidade de milissegundos entre trechos falados consecutivos. O padr\xE3o \xE9 400 ms.",
|
|
1753
1908
|
"dsh-live-voice.speak.segmentGap.label": "Pausa entre trechos de fala",
|
|
1754
1909
|
"dsh-live-voice.speak.status.paused": "Fala pausada",
|
|
1755
|
-
"dsh-live-voice.speak.status.playing": "Falando"
|
|
1910
|
+
"dsh-live-voice.speak.status.playing": "Falando",
|
|
1911
|
+
"dsh-live-voice.speak.volume.help": "Somente reprodu\xE7\xE3o da fala: 0% \xE9 silencioso; 100% \xE9 o volume m\xE1ximo (padr\xE3o). O microfone n\xE3o \xE9 alterado. No Browser, mudan\xE7as valem a partir do pr\xF3ximo trecho.",
|
|
1912
|
+
"dsh-live-voice.speak.volume.label": "Volume da fala"
|
|
1756
1913
|
};
|
|
1757
1914
|
var pt_BR_default = Object.freeze(ptBR);
|
|
1758
1915
|
|
|
@@ -1815,9 +1972,10 @@ var zh = {
|
|
|
1815
1972
|
"dsh-live-voice.commons.version.label": "DSH \u5B9E\u65F6\u8BED\u97F3 v{version}",
|
|
1816
1973
|
"dsh-live-voice.commons.version.link": "DSH \u5B9E\u65F6\u8BED\u97F3 v{version}\u3002\u6253\u5F00\u7248\u672C\u53D1\u5E03\u5217\u8868",
|
|
1817
1974
|
"dsh-live-voice.commons.version.title": "\u7248\u672C\u4FE1\u606F",
|
|
1975
|
+
"dsh-live-voice.meeting.browserLocalUnavailable": "\u6B64\u8BED\u8A00\u7684\u6D4F\u89C8\u5668\u672C\u5730\u8BC6\u522B\u4E0D\u53EF\u7528\u3002\u8BF7\u5B89\u88C5\u8BED\u8A00\u5305\uFF0C\u6216\u5728\u8BBE\u7F6E\u4E2D\u660E\u786E\u5173\u95ED\u4EC5\u672C\u5730\u5904\u7406\uFF0C\u4EE5\u5141\u8BB8\u6D4F\u89C8\u5668\u670D\u52A1\u8BC6\u522B\u3002",
|
|
1976
|
+
"dsh-live-voice.meeting.browserSharedUnsupported": "\u6B64\u6D4F\u89C8\u5668\u65E0\u6CD5\u5B89\u5168\u5730\u8BC6\u522B\u5171\u4EAB\u97F3\u9891\u3002\u8BF7\u4E3A\u5171\u4EAB\u97F3\u9891\u9009\u62E9 Qwen \u6216 Whisper HTTP\u3002",
|
|
1818
1977
|
"dsh-live-voice.meeting.failed": "\u8BED\u97F3\u8BC6\u522B\u5931\u8D25\u3002",
|
|
1819
1978
|
"dsh-live-voice.meeting.help": "\u72EC\u7ACB\u6765\u6E90\uFF1B\u8BF7\u4ECE\u7F16\u8F91\u5668\u624B\u52A8\u53D1\u9001\u8F6C\u5199\u5185\u5BB9\u3002",
|
|
1820
|
-
"dsh-live-voice.meeting.httpRequired": "\u4F1A\u8BAE\u6A21\u5F0F\u9700\u8981 Qwen \u6216 Whisper HTTP\u3002",
|
|
1821
1979
|
"dsh-live-voice.meeting.inactive": "\u672A\u542F\u7528",
|
|
1822
1980
|
"dsh-live-voice.meeting.listening": "\u6B63\u5728\u8046\u542C",
|
|
1823
1981
|
"dsh-live-voice.meeting.microphone": "\u9EA6\u514B\u98CE",
|
|
@@ -1840,10 +1998,13 @@ var zh = {
|
|
|
1840
1998
|
"dsh-live-voice.recognition.browser.localProcessing": "\u5728\u6B64\u8BBE\u5907\u4E0A\u672C\u5730\u5904\u7406\u8BED\u97F3\u8BC6\u522B",
|
|
1841
1999
|
"dsh-live-voice.recognition.browser.microphoneHelp": "\u6D4F\u89C8\u5668 SpeechRecognition \u53EF\u80FD\u4F7F\u7528\u6D4F\u89C8\u5668\u6216\u7CFB\u7EDF\u9ED8\u8BA4\u9EA6\u514B\u98CE\uFF0C\u800C\u975E\u6B64\u5904\u9009\u62E9\u7684\u8BBE\u5907\u3002",
|
|
1842
2000
|
"dsh-live-voice.recognition.browser.remoteServiceWarning": "\u5DF2\u542F\u7528\u6D4F\u89C8\u5668\u670D\u52A1\u8BED\u97F3\u8BC6\u522B\u3002\u6D4F\u89C8\u5668\u53EF\u80FD\u4F1A\u5C06\u9EA6\u514B\u98CE\u97F3\u9891\u53D1\u9001\u81F3\u5176\u8BED\u97F3\u8BC6\u522B\u670D\u52A1\u3002",
|
|
2001
|
+
"dsh-live-voice.recognition.commands.addPhrase": "\u6DFB\u52A0\u77ED\u8BED\u2026",
|
|
1843
2002
|
"dsh-live-voice.recognition.commands.clear": "\u6E05\u7A7A\u6D88\u606F\u8F93\u5165\u6846",
|
|
1844
2003
|
"dsh-live-voice.recognition.commands.enabled": "\u542F\u7528\u7CBE\u786E\u5339\u914D\u7684\u8BED\u97F3\u547D\u4EE4",
|
|
2004
|
+
"dsh-live-voice.recognition.commands.end": "\u7ED3\u675F\u5BF9\u8BDD",
|
|
1845
2005
|
"dsh-live-voice.recognition.commands.mute": "\u505C\u6B62\u5411\u6D88\u606F\u8F93\u5165\u6846\u8F93\u5165\u8BED\u97F3",
|
|
1846
2006
|
"dsh-live-voice.recognition.commands.queue": "\u52A0\u5165\u961F\u5217",
|
|
2007
|
+
"dsh-live-voice.recognition.commands.removePhrase": "\u5220\u9664\u77ED\u8BED",
|
|
1847
2008
|
"dsh-live-voice.recognition.commands.resume": "\u6062\u590D\u5411\u6D88\u606F\u8F93\u5165\u6846\u8F93\u5165\u8BED\u97F3",
|
|
1848
2009
|
"dsh-live-voice.recognition.commands.send": "\u53D1\u9001\u7ED9\u8FD0\u884C\u4E2D\u7684\u667A\u80FD\u4F53",
|
|
1849
2010
|
"dsh-live-voice.recognition.commands.stopSpeech": "\u505C\u6B62\u52A9\u624B\u6717\u8BFB",
|
|
@@ -1856,6 +2017,9 @@ var zh = {
|
|
|
1856
2017
|
"dsh-live-voice.recognition.holdToTalk.help": "\u6D88\u606F\u8F93\u5165\u6846\u6253\u5F00\u65F6\uFF0C\u5728\u9875\u9762\u4EFB\u610F\u4F4D\u7F6E\u6309\u4F4F Control \u952E\u5373\u53EF\u91C7\u96C6\u8BED\u97F3\u3002\u677E\u5F00\u540E\u4F1A\u5904\u7406\u5B8C\u961F\u5217\u4E2D\u7684\u8F6C\u5199\uFF0C\u7B49\u5F85\u8BBE\u5B9A\u7684\u53D1\u9001\u5EF6\u8FDF\uFF0C\u5C06\u6D88\u606F\u52A0\u5165\u961F\u5217\uFF0C\u7136\u540E\u5173\u95ED\u8BED\u97F3\u91C7\u96C6\u3002\u6309\u4F4F\u671F\u95F4\u6309 Escape \u952E\u53EF\u53D6\u6D88\u3002",
|
|
1857
2018
|
"dsh-live-voice.recognition.language.automatic": "\u81EA\u52A8 \u2014 \u68C0\u6D4B\u8BED\u8A00",
|
|
1858
2019
|
"dsh-live-voice.recognition.language.label": "\u8BC6\u522B\u8BED\u8A00",
|
|
2020
|
+
"dsh-live-voice.recognition.language.options.chinese": "\u4E2D\u6587\uFF08\u666E\u901A\u8BDD\uFF09",
|
|
2021
|
+
"dsh-live-voice.recognition.language.options.french": "\u6CD5\u8BED",
|
|
2022
|
+
"dsh-live-voice.recognition.language.options.spanish": "\u897F\u73ED\u7259\u8BED",
|
|
1859
2023
|
"dsh-live-voice.recognition.manualSend.help": "\u8BC6\u522B\u51FA\u7684\u6587\u672C\u4F1A\u4FDD\u7559\u5728\u6D88\u606F\u8F93\u5165\u6846\u4E2D\uFF0C\u76F4\u5230\u4F60\u4F7F\u7528 DSH \u7684\u5E38\u89C4\u53D1\u9001\u6309\u94AE\u3002",
|
|
1860
2024
|
"dsh-live-voice.recognition.maxUtterance.help": "\u5982\u679C\u8BF4\u8BDD\u4E00\u76F4\u6CA1\u6709\u505C\u987F\uFF0C\u5219\u5728\u6B64\u65F6\u957F\u540E\u5F00\u59CB\u65B0\u7684\u8F6C\u5199\u7247\u6BB5\u3002\u9ED8\u8BA4\u503C\uFF1A60 \u79D2\u3002",
|
|
1861
2025
|
"dsh-live-voice.recognition.maxUtterance.label": "\u6700\u957F\u8FDE\u7EED\u8BED\u97F3\uFF08\u79D2\uFF09",
|
|
@@ -1941,8 +2105,19 @@ var zh = {
|
|
|
1941
2105
|
"dsh-live-voice.settings.engine.refresh": "\u5237\u65B0\u53EF\u7528\u5F15\u64CE",
|
|
1942
2106
|
"dsh-live-voice.settings.filters.title": "\u8FC7\u6EE4",
|
|
1943
2107
|
"dsh-live-voice.settings.general.title": "\u5E38\u89C4",
|
|
2108
|
+
"dsh-live-voice.settings.layout.delivery": "\u6D88\u606F\u53D1\u9001",
|
|
2109
|
+
"dsh-live-voice.settings.layout.diagnostics": "\u8BCA\u65AD",
|
|
2110
|
+
"dsh-live-voice.settings.layout.listening": "\u8046\u542C\u4E0E\u6253\u65AD",
|
|
2111
|
+
"dsh-live-voice.settings.layout.playback": "\u64AD\u653E\u4E0E\u8F93\u51FA",
|
|
2112
|
+
"dsh-live-voice.settings.layout.shortcut": "\u5FEB\u6377\u952E",
|
|
2113
|
+
"dsh-live-voice.settings.layout.transcription": "\u8BED\u97F3\u8F6C\u5199",
|
|
2114
|
+
"dsh-live-voice.settings.layout.voice": "\u58F0\u97F3\u4E0E\u5F15\u64CE",
|
|
1944
2115
|
"dsh-live-voice.settings.persistence.loadError": "\u65E0\u6CD5\u4ECE\u670D\u52A1\u5668\u52A0\u8F7D \u5B9E\u65F6\u8BED\u97F3 \u8BBE\u7F6E\u3002\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002",
|
|
1945
2116
|
"dsh-live-voice.settings.persistence.saveError": "\u65E0\u6CD5\u5728\u670D\u52A1\u5668\u4E0A\u4FDD\u5B58 \u5B9E\u65F6\u8BED\u97F3 \u8BBE\u7F6E\u3002\u8BF7\u91CD\u8BD5\u3002",
|
|
2117
|
+
"dsh-live-voice.settings.sourceNames.help": "\u540C\u65F6\u91C7\u96C6\u4E24\u4E2A\u97F3\u6E90\u65F6\uFF0C\u8FD9\u4E9B\u540D\u79F0\u6807\u8BB0\u65B0\u7684\u8F6C\u5F55\u6BB5\u843D\uFF0C\u800C\u975E\u5404\u4E2A\u53C2\u4F1A\u8005\u3002\u79BB\u5F00\u8F93\u5165\u6846\u65F6\u4FDD\u5B58\uFF1B\u7559\u7A7A\u6062\u590D Me / Them\u3002\u6700\u591A 80 \u4E2A\u5B57\u7B26\u3002\u73B0\u6709\u6587\u672C\u4E0D\u4F1A\u6539\u53D8\u3002",
|
|
2118
|
+
"dsh-live-voice.settings.sourceNames.microphone": "\u9EA6\u514B\u98CE\u97F3\u6E90\u540D\u79F0",
|
|
2119
|
+
"dsh-live-voice.settings.sourceNames.shared": "\u5171\u4EAB\u97F3\u9891\u97F3\u6E90\u540D\u79F0",
|
|
2120
|
+
"dsh-live-voice.settings.sourceNames.title": "\u4F1A\u8BAE\u97F3\u6E90\u540D\u79F0",
|
|
1946
2121
|
"dsh-live-voice.settings.tabs.conversation": "\u5BF9\u8BDD",
|
|
1947
2122
|
"dsh-live-voice.settings.tabs.recognition": "\u8BED\u97F3\u8BC6\u522B",
|
|
1948
2123
|
"dsh-live-voice.settings.tabs.speak": "\u8BED\u97F3\u5408\u6210",
|
|
@@ -1956,12 +2131,13 @@ var zh = {
|
|
|
1956
2131
|
"dsh-live-voice.speak.autoPlayback.disable": "\u5173\u95ED\u52A9\u624B\u81EA\u52A8\u6717\u8BFB",
|
|
1957
2132
|
"dsh-live-voice.speak.autoPlayback.enable": "\u5F00\u542F\u52A9\u624B\u81EA\u52A8\u6717\u8BFB",
|
|
1958
2133
|
"dsh-live-voice.speak.autoPlayback.enabled": "\u81EA\u52A8\u6717\u8BFB\u65B0\u7684\u52A9\u624B\u6D88\u606F",
|
|
1959
|
-
"dsh-live-voice.speak.autoPlayback.help": "\
|
|
2134
|
+
"dsh-live-voice.speak.autoPlayback.help": "\u5373\u4F7F\u9EA6\u514B\u98CE\u5173\u95ED\uFF0C\u52A9\u624B\u7684\u65B0\u6D88\u606F\u4E5F\u4F1A\u81EA\u52A8\u6717\u8BFB\u3002\u4F60\u8BF4\u8BDD\u65F6\u4F1A\u7B49\u5F85\uFF0C\u4E0D\u4F1A\u64AD\u653E\u3002",
|
|
1960
2135
|
"dsh-live-voice.speak.autoPlayback.label": "\u52A9\u624B\u81EA\u52A8\u6717\u8BFB",
|
|
1961
2136
|
"dsh-live-voice.speak.autoPlayback.remainingOne": "\u52A9\u624B\u81EA\u52A8\u6717\u8BFB\uFF1A{state} \u2014 \u5269\u4F59 {count} \u4E2A\u8BED\u97F3\u7247\u6BB5",
|
|
1962
2137
|
"dsh-live-voice.speak.autoPlayback.remainingOther": "\u52A9\u624B\u81EA\u52A8\u6717\u8BFB\uFF1A{state} \u2014 \u5269\u4F59 {count} \u4E2A\u8BED\u97F3\u7247\u6BB5",
|
|
1963
2138
|
"dsh-live-voice.speak.autoPlayback.status": "\u52A9\u624B\u81EA\u52A8\u6717\u8BFB\uFF1A{state}",
|
|
1964
2139
|
"dsh-live-voice.speak.browser.automaticVoice": "\u81EA\u52A8\u9009\u62E9\u672C\u5730\u8BED\u97F3",
|
|
2140
|
+
"dsh-live-voice.speak.browser.defaultVoice": "\u9ED8\u8BA4",
|
|
1965
2141
|
"dsh-live-voice.speak.browser.label": "\u6D4F\u89C8\u5668\u8BED\u97F3\u5408\u6210 \u2014 \u5728\u6B64\u8BBE\u5907\u64AD\u653E",
|
|
1966
2142
|
"dsh-live-voice.speak.browser.name": "\u6D4F\u89C8\u5668\u8BED\u97F3\u5408\u6210",
|
|
1967
2143
|
"dsh-live-voice.speak.browser.outputHelp": "\u6D4F\u89C8\u5668\u8BED\u97F3\u5408\u6210\u53EF\u80FD\u5FFD\u7565\u6240\u9009\u8F93\u51FA\u8BBE\u5907\uFF1B\u6B64\u6D4F\u89C8\u5668 API \u901A\u5E38\u4F7F\u7528\u7CFB\u7EDF\u9ED8\u8BA4\u8BBE\u5907\u3002",
|
|
@@ -2029,7 +2205,9 @@ var zh = {
|
|
|
2029
2205
|
"dsh-live-voice.speak.segmentGap.help": "\u5728\u8FDE\u7EED\u8BED\u97F3\u7247\u6BB5\u4E4B\u95F4\u7B49\u5F85\u6B64\u6BEB\u79D2\u6570\u3002\u9ED8\u8BA4\u503C\u4E3A 400 ms\u3002",
|
|
2030
2206
|
"dsh-live-voice.speak.segmentGap.label": "\u8BED\u97F3\u7247\u6BB5\u4E4B\u95F4\u7684\u505C\u987F",
|
|
2031
2207
|
"dsh-live-voice.speak.status.paused": "\u8BED\u97F3\u5DF2\u6682\u505C",
|
|
2032
|
-
"dsh-live-voice.speak.status.playing": "\u6B63\u5728\u6717\u8BFB"
|
|
2208
|
+
"dsh-live-voice.speak.status.playing": "\u6B63\u5728\u6717\u8BFB",
|
|
2209
|
+
"dsh-live-voice.speak.volume.help": "\u4EC5\u8C03\u6574\u8BED\u97F3\u64AD\u653E\uFF1A0% \u4E3A\u9759\u97F3\uFF0C100% \u4E3A\u6700\u5927\u97F3\u91CF\uFF08\u9ED8\u8BA4\uFF09\u3002\u4E0D\u6539\u53D8\u9EA6\u514B\u98CE\u8F93\u5165\u3002Browser \u7684\u66F4\u6539\u4ECE\u4E0B\u4E00\u8BED\u97F3\u7247\u6BB5\u751F\u6548\u3002",
|
|
2210
|
+
"dsh-live-voice.speak.volume.label": "\u8BED\u97F3\u97F3\u91CF"
|
|
2033
2211
|
};
|
|
2034
2212
|
var zh_default = Object.freeze(zh);
|
|
2035
2213
|
|
|
@@ -2233,6 +2411,11 @@ var import_react3 = __toESM(require("react"), 1);
|
|
|
2233
2411
|
|
|
2234
2412
|
// src/shared/design-system/icons/icons.ts
|
|
2235
2413
|
var iconPaths = {
|
|
2414
|
+
conversation: "M4 3h16v13H8l-4 4V3M8 7h8M8 11h5",
|
|
2415
|
+
keyboard: "M3 6h18v12H3V6M7 10h.01M11 10h.01M15 10h.01M18 10h.01M7 14h10",
|
|
2416
|
+
headphones: "M3 14v-3a9 9 0 0 1 18 0v3M3 12h4v8H3v-8M17 12h4v8h-4v-8",
|
|
2417
|
+
commands: "M3 6l2 2 3-4M11 6h10M3 14l2 2 3-4M11 14h10M11 20h10",
|
|
2418
|
+
bug: "M8 8h8v9a4 4 0 0 1-8 0V8M9 8V6a3 3 0 0 1 6 0v2M3 9l5 2M16 11l5-2M3 16h5M16 16h5M5 22l3-3M16 19l3 3",
|
|
2236
2419
|
meeting: "M8 3a3 3 0 1 0 0 6 3 3 0 0 0 0-6M16 4a3 3 0 1 0 0 6 3 3 0 0 0 0-6M2 20v-3a6 6 0 0 1 12 0v3M16 13a5 5 0 0 1 6 5v2",
|
|
2237
2420
|
meetingOff: "M8 3a3 3 0 1 0 0 6 3 3 0 0 0 0-6M16 4a3 3 0 1 0 0 6 3 3 0 0 0 0-6M2 20v-3a6 6 0 0 1 12 0v3M17 16l5 5M22 16l-5 5",
|
|
2238
2421
|
mic: "M9 5a3 3 0 0 1 6 0v7a3 3 0 0 1-6 0V5M6 10v2a6 6 0 0 0 12 0v-2M12 18v4M8 22h8",
|
|
@@ -2330,22 +2513,134 @@ var import_react8 = __toESM(require("react"), 1);
|
|
|
2330
2513
|
// src/shared/design-system/feedback/StatusMessage.tsx
|
|
2331
2514
|
var import_react9 = __toESM(require("react"), 1);
|
|
2332
2515
|
|
|
2333
|
-
// src/shared/design-system/
|
|
2516
|
+
// src/shared/design-system/feedback/Hint.tsx
|
|
2334
2517
|
var import_react10 = __toESM(require("react"), 1);
|
|
2518
|
+
function Hint({
|
|
2519
|
+
label,
|
|
2520
|
+
children,
|
|
2521
|
+
id: suppliedId
|
|
2522
|
+
}) {
|
|
2523
|
+
const generatedId = import_react10.default.useId();
|
|
2524
|
+
const id2 = suppliedId || generatedId;
|
|
2525
|
+
const [open, setOpen] = import_react10.default.useState(false);
|
|
2526
|
+
const trigger = import_react10.default.useRef(null);
|
|
2527
|
+
const bubble = import_react10.default.useRef(null);
|
|
2528
|
+
const hovered = import_react10.default.useRef(false);
|
|
2529
|
+
const focused = import_react10.default.useRef(false);
|
|
2530
|
+
const timer = import_react10.default.useRef(void 0);
|
|
2531
|
+
const cancel = () => clearTimeout(timer.current);
|
|
2532
|
+
const closeLater = () => {
|
|
2533
|
+
cancel();
|
|
2534
|
+
timer.current = setTimeout(() => {
|
|
2535
|
+
if (!hovered.current && !focused.current) setOpen(false);
|
|
2536
|
+
}, 120);
|
|
2537
|
+
};
|
|
2538
|
+
import_react10.default.useEffect(() => () => clearTimeout(timer.current), []);
|
|
2539
|
+
import_react10.default.useLayoutEffect(() => {
|
|
2540
|
+
const node = bubble.current;
|
|
2541
|
+
if (!open || !node || !trigger.current) return;
|
|
2542
|
+
node.showPopover?.();
|
|
2543
|
+
const position = () => {
|
|
2544
|
+
const anchor = trigger.current.getBoundingClientRect();
|
|
2545
|
+
const rect = node.getBoundingClientRect();
|
|
2546
|
+
node.style.left = Math.max(12, Math.min(anchor.left, window.innerWidth - rect.width - 12)) + "px";
|
|
2547
|
+
const below = anchor.bottom + 8;
|
|
2548
|
+
node.style.top = Math.max(
|
|
2549
|
+
12,
|
|
2550
|
+
below + rect.height <= window.innerHeight - 12 ? below : anchor.top - rect.height - 8
|
|
2551
|
+
) + "px";
|
|
2552
|
+
};
|
|
2553
|
+
position();
|
|
2554
|
+
const dismiss = (e) => {
|
|
2555
|
+
if (e.key === "Escape") {
|
|
2556
|
+
e.stopPropagation();
|
|
2557
|
+
setOpen(false);
|
|
2558
|
+
}
|
|
2559
|
+
};
|
|
2560
|
+
const outside = (e) => {
|
|
2561
|
+
if (!node.contains(e.target) && !trigger.current?.contains(e.target))
|
|
2562
|
+
setOpen(false);
|
|
2563
|
+
};
|
|
2564
|
+
document.addEventListener("keydown", dismiss, true);
|
|
2565
|
+
document.addEventListener("pointerdown", outside, true);
|
|
2566
|
+
window.addEventListener("resize", position);
|
|
2567
|
+
window.addEventListener("scroll", position, true);
|
|
2568
|
+
return () => {
|
|
2569
|
+
node.hidePopover?.();
|
|
2570
|
+
document.removeEventListener("keydown", dismiss, true);
|
|
2571
|
+
document.removeEventListener("pointerdown", outside, true);
|
|
2572
|
+
window.removeEventListener("resize", position);
|
|
2573
|
+
window.removeEventListener("scroll", position, true);
|
|
2574
|
+
};
|
|
2575
|
+
}, [open]);
|
|
2576
|
+
return /* @__PURE__ */ import_react10.default.createElement(
|
|
2577
|
+
"span",
|
|
2578
|
+
{
|
|
2579
|
+
className: "dlv-hint",
|
|
2580
|
+
onMouseEnter: () => {
|
|
2581
|
+
hovered.current = true;
|
|
2582
|
+
cancel();
|
|
2583
|
+
setOpen(true);
|
|
2584
|
+
},
|
|
2585
|
+
onMouseLeave: () => {
|
|
2586
|
+
hovered.current = false;
|
|
2587
|
+
closeLater();
|
|
2588
|
+
}
|
|
2589
|
+
},
|
|
2590
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
2591
|
+
"button",
|
|
2592
|
+
{
|
|
2593
|
+
ref: trigger,
|
|
2594
|
+
type: "button",
|
|
2595
|
+
className: "dlv-hint-trigger",
|
|
2596
|
+
"aria-label": label,
|
|
2597
|
+
"aria-describedby": open ? id2 : void 0,
|
|
2598
|
+
"aria-expanded": open,
|
|
2599
|
+
onFocus: () => {
|
|
2600
|
+
focused.current = true;
|
|
2601
|
+
cancel();
|
|
2602
|
+
setOpen(true);
|
|
2603
|
+
},
|
|
2604
|
+
onBlur: () => {
|
|
2605
|
+
focused.current = false;
|
|
2606
|
+
closeLater();
|
|
2607
|
+
},
|
|
2608
|
+
onClick: () => setOpen(true)
|
|
2609
|
+
},
|
|
2610
|
+
"?"
|
|
2611
|
+
),
|
|
2612
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
2613
|
+
"span",
|
|
2614
|
+
{
|
|
2615
|
+
ref: bubble,
|
|
2616
|
+
id: id2,
|
|
2617
|
+
role: "tooltip",
|
|
2618
|
+
popover: "manual",
|
|
2619
|
+
hidden: !open,
|
|
2620
|
+
className: "dlv-hint-bubble"
|
|
2621
|
+
},
|
|
2622
|
+
children
|
|
2623
|
+
)
|
|
2624
|
+
);
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
// src/shared/design-system/forms/CheckboxField.tsx
|
|
2628
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
2335
2629
|
function CheckboxField({
|
|
2336
2630
|
label,
|
|
2337
2631
|
description,
|
|
2632
|
+
hint,
|
|
2338
2633
|
className = "dlv-check",
|
|
2339
2634
|
...props
|
|
2340
2635
|
}) {
|
|
2341
|
-
return /* @__PURE__ */
|
|
2636
|
+
return /* @__PURE__ */ import_react11.default.createElement("div", null, /* @__PURE__ */ import_react11.default.createElement("div", { className: "dlv-field-label" }, /* @__PURE__ */ import_react11.default.createElement("label", { className }, /* @__PURE__ */ import_react11.default.createElement("input", { ...props, type: "checkbox" }), " ", label), hint && /* @__PURE__ */ import_react11.default.createElement(Hint, { label }, hint)), description ? /* @__PURE__ */ import_react11.default.createElement("p", { className: "dlv-setting-description" }, description) : null);
|
|
2342
2637
|
}
|
|
2343
2638
|
|
|
2344
2639
|
// src/shared/design-system/forms/NumberField.tsx
|
|
2345
|
-
var
|
|
2640
|
+
var import_react13 = __toESM(require("react"), 1);
|
|
2346
2641
|
|
|
2347
2642
|
// src/shared/design-system/forms/DraftField.tsx
|
|
2348
|
-
var
|
|
2643
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
2349
2644
|
function DraftField({
|
|
2350
2645
|
label,
|
|
2351
2646
|
value,
|
|
@@ -2359,10 +2654,10 @@ function DraftField({
|
|
|
2359
2654
|
...props
|
|
2360
2655
|
}) {
|
|
2361
2656
|
const saved = String(value ?? defaultValue ?? "");
|
|
2362
|
-
const [draft, setDraft] =
|
|
2363
|
-
const editing =
|
|
2364
|
-
const dirty =
|
|
2365
|
-
|
|
2657
|
+
const [draft, setDraft] = import_react12.default.useState(saved);
|
|
2658
|
+
const editing = import_react12.default.useRef(false);
|
|
2659
|
+
const dirty = import_react12.default.useRef(false);
|
|
2660
|
+
import_react12.default.useEffect(() => {
|
|
2366
2661
|
if (!editing.current) setDraft(saved);
|
|
2367
2662
|
}, [saved]);
|
|
2368
2663
|
const inputProps = {
|
|
@@ -2395,46 +2690,73 @@ function DraftField({
|
|
|
2395
2690
|
onBlur?.(event);
|
|
2396
2691
|
}
|
|
2397
2692
|
};
|
|
2398
|
-
return /* @__PURE__ */
|
|
2693
|
+
return /* @__PURE__ */ import_react12.default.createElement("label", null, label, multiline ? /* @__PURE__ */ import_react12.default.createElement("textarea", { ...inputProps }) : /* @__PURE__ */ import_react12.default.createElement("input", { ...inputProps }));
|
|
2399
2694
|
}
|
|
2400
2695
|
|
|
2401
2696
|
// src/shared/design-system/forms/NumberField.tsx
|
|
2402
2697
|
function NumberField(props) {
|
|
2403
|
-
return /* @__PURE__ */
|
|
2698
|
+
return /* @__PURE__ */ import_react13.default.createElement(DraftField, { ...props, type: "number" });
|
|
2404
2699
|
}
|
|
2405
2700
|
|
|
2406
2701
|
// src/shared/design-system/forms/SelectField.tsx
|
|
2407
|
-
var
|
|
2408
|
-
function SelectField({ label, options, ...props }) {
|
|
2409
|
-
|
|
2702
|
+
var import_react14 = __toESM(require("react"), 1);
|
|
2703
|
+
function SelectField({ label, options, hint, ...props }) {
|
|
2704
|
+
const generatedId = import_react14.default.useId();
|
|
2705
|
+
const id2 = props.id || generatedId;
|
|
2706
|
+
return /* @__PURE__ */ import_react14.default.createElement("div", { className: "dlv-form-field" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "dlv-field-label" }, /* @__PURE__ */ import_react14.default.createElement("label", { htmlFor: id2 }, label), hint && /* @__PURE__ */ import_react14.default.createElement(Hint, { label, id: props["aria-describedby"] }, hint)), /* @__PURE__ */ import_react14.default.createElement("select", { ...props, id: id2 }, options.map(
|
|
2707
|
+
(option) => "options" in option ? /* @__PURE__ */ import_react14.default.createElement("optgroup", { key: option.label, label: option.label }, option.options.map((item) => /* @__PURE__ */ import_react14.default.createElement("option", { key: item.value, value: item.value, disabled: item.disabled }, item.label))) : /* @__PURE__ */ import_react14.default.createElement("option", { key: option.value, value: option.value, disabled: option.disabled }, option.label)
|
|
2708
|
+
)));
|
|
2410
2709
|
}
|
|
2411
2710
|
|
|
2412
2711
|
// src/shared/design-system/forms/TextAreaField.tsx
|
|
2413
|
-
var
|
|
2712
|
+
var import_react15 = __toESM(require("react"), 1);
|
|
2414
2713
|
function TextAreaField(props) {
|
|
2415
|
-
return /* @__PURE__ */
|
|
2714
|
+
return /* @__PURE__ */ import_react15.default.createElement(DraftField, { ...props, multiline: true });
|
|
2416
2715
|
}
|
|
2417
2716
|
|
|
2418
2717
|
// src/shared/design-system/forms/TextField.tsx
|
|
2419
|
-
var
|
|
2718
|
+
var import_react16 = __toESM(require("react"), 1);
|
|
2420
2719
|
function TextField(props) {
|
|
2421
|
-
return /* @__PURE__ */
|
|
2720
|
+
return /* @__PURE__ */ import_react16.default.createElement(DraftField, { ...props, type: "text" });
|
|
2422
2721
|
}
|
|
2423
2722
|
|
|
2424
2723
|
// src/shared/design-system/layout/SettingsCard.tsx
|
|
2425
|
-
var
|
|
2724
|
+
var import_react17 = __toESM(require("react"), 1);
|
|
2426
2725
|
function SettingsCard({
|
|
2427
2726
|
children,
|
|
2428
2727
|
className = ""
|
|
2429
2728
|
}) {
|
|
2430
|
-
return /* @__PURE__ */
|
|
2729
|
+
return /* @__PURE__ */ import_react17.default.createElement("div", { className: ["dlv-settings-card", className].filter(Boolean).join(" ") }, children);
|
|
2431
2730
|
}
|
|
2432
2731
|
|
|
2433
2732
|
// src/shared/design-system/layout/SettingsSection.tsx
|
|
2434
|
-
var
|
|
2733
|
+
var import_react19 = __toESM(require("react"), 1);
|
|
2435
2734
|
|
|
2436
|
-
// src/shared/design-system/layout/
|
|
2735
|
+
// src/shared/design-system/layout/SettingsSectionBody.tsx
|
|
2437
2736
|
var import_react18 = __toESM(require("react"), 1);
|
|
2737
|
+
function SettingsSectionBody({ children }) {
|
|
2738
|
+
return /* @__PURE__ */ import_react18.default.createElement("div", { className: "dlv-section-content" }, children);
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
// src/shared/design-system/layout/SettingsSection.tsx
|
|
2742
|
+
function SettingsSection({
|
|
2743
|
+
title,
|
|
2744
|
+
children,
|
|
2745
|
+
icon,
|
|
2746
|
+
description,
|
|
2747
|
+
collapsible = true,
|
|
2748
|
+
defaultOpen = true,
|
|
2749
|
+
ariaLabel
|
|
2750
|
+
}) {
|
|
2751
|
+
const heading = /* @__PURE__ */ import_react19.default.createElement("h4", null, icon && /* @__PURE__ */ import_react19.default.createElement(Icon, { name: icon }), title);
|
|
2752
|
+
const body = /* @__PURE__ */ import_react19.default.createElement(SettingsSectionBody, null, description && /* @__PURE__ */ import_react19.default.createElement("p", null, description), children);
|
|
2753
|
+
if (!collapsible)
|
|
2754
|
+
return /* @__PURE__ */ import_react19.default.createElement("section", { className: "dlv-settings-section" }, /* @__PURE__ */ import_react19.default.createElement("header", { className: "dlv-section-heading" }, heading), body);
|
|
2755
|
+
return /* @__PURE__ */ import_react19.default.createElement("details", { className: "dlv-settings-section", open: defaultOpen }, /* @__PURE__ */ import_react19.default.createElement("summary", { className: "dlv-section-heading", "aria-label": ariaLabel }, heading, /* @__PURE__ */ import_react19.default.createElement(Icon, { name: "chevron", className: "dlv-section-chevron" })), body);
|
|
2756
|
+
}
|
|
2757
|
+
|
|
2758
|
+
// src/shared/design-system/layout/SettingsSubcard.tsx
|
|
2759
|
+
var import_react20 = __toESM(require("react"), 1);
|
|
2438
2760
|
function SettingsSubcard({
|
|
2439
2761
|
title,
|
|
2440
2762
|
children,
|
|
@@ -2442,13 +2764,13 @@ function SettingsSubcard({
|
|
|
2442
2764
|
ariaLabel,
|
|
2443
2765
|
icon = "settings"
|
|
2444
2766
|
}) {
|
|
2445
|
-
return /* @__PURE__ */
|
|
2767
|
+
return /* @__PURE__ */ import_react20.default.createElement("details", { className: "dlv-settings-subcard", open }, /* @__PURE__ */ import_react20.default.createElement("summary", { "aria-label": ariaLabel }, /* @__PURE__ */ import_react20.default.createElement(Icon, { name: icon, className: "dlv-settings-subcard-icon" }), /* @__PURE__ */ import_react20.default.createElement("span", null, title), /* @__PURE__ */ import_react20.default.createElement(Icon, { name: "chevron", className: "dlv-settings-subcard-chevron" })), /* @__PURE__ */ import_react20.default.createElement("div", { className: "dlv-settings-subcard-body" }, children));
|
|
2446
2768
|
}
|
|
2447
2769
|
|
|
2448
2770
|
// src/shared/design-system/layout/SettingsTabs.tsx
|
|
2449
|
-
var
|
|
2771
|
+
var import_react21 = __toESM(require("react"), 1);
|
|
2450
2772
|
function SettingsTabs({ label, tabs, active, idPrefix, onChange }) {
|
|
2451
|
-
const refs =
|
|
2773
|
+
const refs = import_react21.default.useRef([]);
|
|
2452
2774
|
const activate = (index) => {
|
|
2453
2775
|
const tab = tabs[index];
|
|
2454
2776
|
if (!tab) return;
|
|
@@ -2465,7 +2787,7 @@ function SettingsTabs({ label, tabs, active, idPrefix, onChange }) {
|
|
|
2465
2787
|
event.preventDefault();
|
|
2466
2788
|
activate(next);
|
|
2467
2789
|
};
|
|
2468
|
-
return /* @__PURE__ */
|
|
2790
|
+
return /* @__PURE__ */ import_react21.default.createElement("div", { className: "dlv-settings-tabs", role: "tablist", "aria-label": label }, tabs.map((tab, index) => /* @__PURE__ */ import_react21.default.createElement(
|
|
2469
2791
|
"button",
|
|
2470
2792
|
{
|
|
2471
2793
|
key: tab.id,
|
|
@@ -2483,23 +2805,23 @@ function SettingsTabs({ label, tabs, active, idPrefix, onChange }) {
|
|
|
2483
2805
|
onClick: () => onChange(tab.id),
|
|
2484
2806
|
onKeyDown: (event) => onKeyDown(event, index)
|
|
2485
2807
|
},
|
|
2486
|
-
tab.icon ? /* @__PURE__ */
|
|
2487
|
-
/* @__PURE__ */
|
|
2808
|
+
tab.icon ? /* @__PURE__ */ import_react21.default.createElement(Icon, { name: tab.icon, className: "dlv-settings-tab-icon" }) : null,
|
|
2809
|
+
/* @__PURE__ */ import_react21.default.createElement("span", null, tab.label)
|
|
2488
2810
|
)));
|
|
2489
2811
|
}
|
|
2490
2812
|
|
|
2491
2813
|
// src/modules/conversation/hooks/useConversationActions.ts
|
|
2492
|
-
var
|
|
2814
|
+
var import_react22 = __toESM(require("react"), 1);
|
|
2493
2815
|
function useConversationActions(controller) {
|
|
2494
|
-
const [error, setError] =
|
|
2495
|
-
const alive =
|
|
2496
|
-
|
|
2816
|
+
const [error, setError] = import_react22.default.useState("");
|
|
2817
|
+
const alive = import_react22.default.useRef(true);
|
|
2818
|
+
import_react22.default.useEffect(
|
|
2497
2819
|
() => () => {
|
|
2498
2820
|
alive.current = false;
|
|
2499
2821
|
},
|
|
2500
2822
|
[]
|
|
2501
2823
|
);
|
|
2502
|
-
const invoke =
|
|
2824
|
+
const invoke = import_react22.default.useCallback(
|
|
2503
2825
|
(name, ...args) => {
|
|
2504
2826
|
setError("");
|
|
2505
2827
|
try {
|
|
@@ -2512,23 +2834,23 @@ function useConversationActions(controller) {
|
|
|
2512
2834
|
},
|
|
2513
2835
|
[controller]
|
|
2514
2836
|
);
|
|
2515
|
-
const clearError =
|
|
2837
|
+
const clearError = import_react22.default.useCallback(() => setError(""), []);
|
|
2516
2838
|
return { invoke, error, clearError };
|
|
2517
2839
|
}
|
|
2518
2840
|
|
|
2519
2841
|
// src/modules/conversation/hooks/useConversationController.ts
|
|
2520
|
-
var
|
|
2842
|
+
var import_react23 = __toESM(require("react"), 1);
|
|
2521
2843
|
function useConversationController(controller) {
|
|
2522
|
-
const subscribe =
|
|
2844
|
+
const subscribe = import_react23.default.useCallback(
|
|
2523
2845
|
(listener) => controller.subscribe(listener),
|
|
2524
2846
|
[controller]
|
|
2525
2847
|
);
|
|
2526
|
-
const read =
|
|
2527
|
-
return
|
|
2848
|
+
const read = import_react23.default.useCallback(() => controller.getSnapshot(), [controller]);
|
|
2849
|
+
return import_react23.default.useSyncExternalStore(subscribe, read, read);
|
|
2528
2850
|
}
|
|
2529
2851
|
|
|
2530
2852
|
// src/modules/conversation/components/PlaybackControls.tsx
|
|
2531
|
-
var
|
|
2853
|
+
var import_react24 = __toESM(require("react"), 1);
|
|
2532
2854
|
function PlaybackControls({
|
|
2533
2855
|
state,
|
|
2534
2856
|
invoke,
|
|
@@ -2536,21 +2858,21 @@ function PlaybackControls({
|
|
|
2536
2858
|
}) {
|
|
2537
2859
|
const { scoped: speak } = useLanguage((ctx) => ctx.speak);
|
|
2538
2860
|
const capabilities = state.capabilities?.[state.speechEngine || state.settings?.engine] ?? {};
|
|
2539
|
-
return /* @__PURE__ */
|
|
2861
|
+
return /* @__PURE__ */ import_react24.default.createElement(import_react24.default.Fragment, null, navigation && state.speechHasPrevious ? /* @__PURE__ */ import_react24.default.createElement(
|
|
2540
2862
|
IconButton,
|
|
2541
2863
|
{
|
|
2542
2864
|
label: speak.playback.previous(),
|
|
2543
2865
|
icon: "skipPrevious",
|
|
2544
2866
|
onClick: () => invoke("previousSpeechSegment")
|
|
2545
2867
|
}
|
|
2546
|
-
) : null, navigation && state.speechSegmentsRemaining > 1 ? /* @__PURE__ */
|
|
2868
|
+
) : null, navigation && state.speechSegmentsRemaining > 1 ? /* @__PURE__ */ import_react24.default.createElement(
|
|
2547
2869
|
IconButton,
|
|
2548
2870
|
{
|
|
2549
2871
|
label: speak.playback.next(),
|
|
2550
2872
|
icon: "skipNext",
|
|
2551
2873
|
onClick: () => invoke("skipSpeechSegment")
|
|
2552
2874
|
}
|
|
2553
|
-
) : null, state.speechSegmentsRemaining > 0 && capabilities.pause && !state.paused ? /* @__PURE__ */
|
|
2875
|
+
) : null, state.speechSegmentsRemaining > 0 && capabilities.pause && !state.paused ? /* @__PURE__ */ import_react24.default.createElement(
|
|
2554
2876
|
IconButton,
|
|
2555
2877
|
{
|
|
2556
2878
|
label: speak.playback.pause(),
|
|
@@ -2558,14 +2880,14 @@ function PlaybackControls({
|
|
|
2558
2880
|
disabled: !state.speaking || state.paused,
|
|
2559
2881
|
onClick: () => invoke("pauseSpeech")
|
|
2560
2882
|
}
|
|
2561
|
-
) : null, state.paused && capabilities.resume ? /* @__PURE__ */
|
|
2883
|
+
) : null, state.paused && capabilities.resume ? /* @__PURE__ */ import_react24.default.createElement(
|
|
2562
2884
|
IconButton,
|
|
2563
2885
|
{
|
|
2564
2886
|
label: speak.playback.resume(),
|
|
2565
2887
|
icon: "play",
|
|
2566
2888
|
onClick: () => invoke("resumeSpeech")
|
|
2567
2889
|
}
|
|
2568
|
-
) : null, state.speechSegmentsRemaining > 0 || state.speechRunActive ? /* @__PURE__ */
|
|
2890
|
+
) : null, state.speechSegmentsRemaining > 0 || state.speechRunActive ? /* @__PURE__ */ import_react24.default.createElement(
|
|
2569
2891
|
IconButton,
|
|
2570
2892
|
{
|
|
2571
2893
|
label: speak.playback.stopAll(),
|
|
@@ -2576,7 +2898,7 @@ function PlaybackControls({
|
|
|
2576
2898
|
}
|
|
2577
2899
|
|
|
2578
2900
|
// src/modules/conversation/components/ScrollingSpeechCaption.tsx
|
|
2579
|
-
var
|
|
2901
|
+
var import_react25 = __toESM(require("react"), 1);
|
|
2580
2902
|
function ScrollingSpeechCaption({
|
|
2581
2903
|
text,
|
|
2582
2904
|
label,
|
|
@@ -2585,12 +2907,12 @@ function ScrollingSpeechCaption({
|
|
|
2585
2907
|
paused,
|
|
2586
2908
|
loading
|
|
2587
2909
|
}) {
|
|
2588
|
-
const viewport =
|
|
2589
|
-
const line =
|
|
2590
|
-
const marker =
|
|
2591
|
-
const current =
|
|
2910
|
+
const viewport = import_react25.default.useRef(null);
|
|
2911
|
+
const line = import_react25.default.useRef(null);
|
|
2912
|
+
const marker = import_react25.default.useRef(null);
|
|
2913
|
+
const current = import_react25.default.useRef({ paused, loading });
|
|
2592
2914
|
current.current = { paused, loading };
|
|
2593
|
-
|
|
2915
|
+
import_react25.default.useEffect(() => {
|
|
2594
2916
|
const box = viewport.current;
|
|
2595
2917
|
const content = line.current;
|
|
2596
2918
|
const band = marker.current;
|
|
@@ -2643,7 +2965,7 @@ function ScrollingSpeechCaption({
|
|
|
2643
2965
|
observer?.disconnect();
|
|
2644
2966
|
};
|
|
2645
2967
|
}, [controller, text, segment]);
|
|
2646
|
-
return /* @__PURE__ */
|
|
2968
|
+
return /* @__PURE__ */ import_react25.default.createElement("div", { className: "dlv-caption-stage" }, /* @__PURE__ */ import_react25.default.createElement(
|
|
2647
2969
|
"div",
|
|
2648
2970
|
{
|
|
2649
2971
|
ref: viewport,
|
|
@@ -2651,8 +2973,8 @@ function ScrollingSpeechCaption({
|
|
|
2651
2973
|
title: text,
|
|
2652
2974
|
"aria-label": label
|
|
2653
2975
|
},
|
|
2654
|
-
/* @__PURE__ */
|
|
2655
|
-
), /* @__PURE__ */
|
|
2976
|
+
/* @__PURE__ */ import_react25.default.createElement("span", { ref: line, className: "dlv-caption-line" }, text)
|
|
2977
|
+
), /* @__PURE__ */ import_react25.default.createElement("span", { ref: marker, className: "dlv-caption-marker", "aria-hidden": "true" }));
|
|
2656
2978
|
}
|
|
2657
2979
|
|
|
2658
2980
|
// src/modules/conversation/components/SpeechStatusBar.tsx
|
|
@@ -2661,8 +2983,8 @@ function SpeechStatusBar({ controller }) {
|
|
|
2661
2983
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
2662
2984
|
const state = useConversationController(controller);
|
|
2663
2985
|
const { invoke, error, clearError } = useConversationActions(controller);
|
|
2664
|
-
const [progress, setProgress] =
|
|
2665
|
-
|
|
2986
|
+
const [progress, setProgress] = import_react26.default.useState(null);
|
|
2987
|
+
import_react26.default.useEffect(() => {
|
|
2666
2988
|
setProgress(null);
|
|
2667
2989
|
if (!state.speechText || !state.speaking) return;
|
|
2668
2990
|
const update = () => setProgress(controller.getSpeechProgress?.() ?? null);
|
|
@@ -2678,14 +3000,14 @@ function SpeechStatusBar({ controller }) {
|
|
|
2678
3000
|
const loading = state.speechLoading === true && state.speaking && !state.paused;
|
|
2679
3001
|
const index = state.speechSegmentIndex ?? 0;
|
|
2680
3002
|
const total = state.speechSegmentsTotal ?? state.speechSegmentsRemaining ?? 0;
|
|
2681
|
-
return /* @__PURE__ */
|
|
3003
|
+
return /* @__PURE__ */ import_react26.default.createElement("div", { className: "dlv-bar-wrap dlv-speech-bar" }, /* @__PURE__ */ import_react26.default.createElement(
|
|
2682
3004
|
"div",
|
|
2683
3005
|
{
|
|
2684
3006
|
className: "dlv-pill dlv-speech-pill",
|
|
2685
3007
|
role: "group",
|
|
2686
3008
|
"aria-label": speak.captions.title()
|
|
2687
3009
|
},
|
|
2688
|
-
/* @__PURE__ */
|
|
3010
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
2689
3011
|
IconButton,
|
|
2690
3012
|
{
|
|
2691
3013
|
label: speak.playback.previous(),
|
|
@@ -2694,7 +3016,7 @@ function SpeechStatusBar({ controller }) {
|
|
|
2694
3016
|
onClick: () => invoke("previousSpeechSegment")
|
|
2695
3017
|
}
|
|
2696
3018
|
),
|
|
2697
|
-
/* @__PURE__ */
|
|
3019
|
+
/* @__PURE__ */ import_react26.default.createElement("div", { className: "dlv-caption-stack" }, /* @__PURE__ */ import_react26.default.createElement(
|
|
2698
3020
|
ScrollingSpeechCaption,
|
|
2699
3021
|
{
|
|
2700
3022
|
text,
|
|
@@ -2704,7 +3026,7 @@ function SpeechStatusBar({ controller }) {
|
|
|
2704
3026
|
paused: state.paused || !state.speaking,
|
|
2705
3027
|
loading
|
|
2706
3028
|
}
|
|
2707
|
-
), /* @__PURE__ */
|
|
3029
|
+
), /* @__PURE__ */ import_react26.default.createElement(
|
|
2708
3030
|
"div",
|
|
2709
3031
|
{
|
|
2710
3032
|
className: "dlv-caption-progress",
|
|
@@ -2716,9 +3038,9 @@ function SpeechStatusBar({ controller }) {
|
|
|
2716
3038
|
"aria-valuemax": 100,
|
|
2717
3039
|
"aria-valuenow": loading || ratio === null ? void 0 : Math.round(ratio * 100)
|
|
2718
3040
|
},
|
|
2719
|
-
/* @__PURE__ */
|
|
3041
|
+
/* @__PURE__ */ import_react26.default.createElement("span", { style: loading ? void 0 : { width: (ratio ?? 0) * 100 + "%" } })
|
|
2720
3042
|
)),
|
|
2721
|
-
/* @__PURE__ */
|
|
3043
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
2722
3044
|
IconButton,
|
|
2723
3045
|
{
|
|
2724
3046
|
label: speak.playback.next(),
|
|
@@ -2727,7 +3049,7 @@ function SpeechStatusBar({ controller }) {
|
|
|
2727
3049
|
onClick: () => invoke("skipSpeechSegment")
|
|
2728
3050
|
}
|
|
2729
3051
|
),
|
|
2730
|
-
/* @__PURE__ */
|
|
3052
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
2731
3053
|
"span",
|
|
2732
3054
|
{
|
|
2733
3055
|
className: "dlv-speech-count",
|
|
@@ -2737,8 +3059,8 @@ function SpeechStatusBar({ controller }) {
|
|
|
2737
3059
|
"/",
|
|
2738
3060
|
total
|
|
2739
3061
|
),
|
|
2740
|
-
/* @__PURE__ */
|
|
2741
|
-
), /* @__PURE__ */
|
|
3062
|
+
/* @__PURE__ */ import_react26.default.createElement(PlaybackControls, { state, invoke, navigation: false })
|
|
3063
|
+
), /* @__PURE__ */ import_react26.default.createElement(
|
|
2742
3064
|
ErrorMessage,
|
|
2743
3065
|
{
|
|
2744
3066
|
error,
|
|
@@ -2749,67 +3071,6 @@ function SpeechStatusBar({ controller }) {
|
|
|
2749
3071
|
));
|
|
2750
3072
|
}
|
|
2751
3073
|
|
|
2752
|
-
// src/modules/conversation/models/meetingTranscript.ts
|
|
2753
|
-
var MeetingTranscript = class {
|
|
2754
|
-
constructor(composer) {
|
|
2755
|
-
this.composer = composer;
|
|
2756
|
-
}
|
|
2757
|
-
composer;
|
|
2758
|
-
active = /* @__PURE__ */ new Set();
|
|
2759
|
-
last = null;
|
|
2760
|
-
expected = null;
|
|
2761
|
-
timestamps = false;
|
|
2762
|
-
sourceTimestamps = /* @__PURE__ */ new Map();
|
|
2763
|
-
setSourceTimestamps(source, enabled) {
|
|
2764
|
-
if (this.sourceTimestamps.get(source) === enabled) return;
|
|
2765
|
-
this.sourceTimestamps.set(source, enabled);
|
|
2766
|
-
this.last = null;
|
|
2767
|
-
}
|
|
2768
|
-
setTimestamps(enabled) {
|
|
2769
|
-
this.timestamps = enabled;
|
|
2770
|
-
this.last = null;
|
|
2771
|
-
}
|
|
2772
|
-
setActive(source, enabled) {
|
|
2773
|
-
if (enabled) this.active.add(source);
|
|
2774
|
-
else this.active.delete(source);
|
|
2775
|
-
this.last = null;
|
|
2776
|
-
}
|
|
2777
|
-
append(source, text, startedAt) {
|
|
2778
|
-
const chunk = text.trim();
|
|
2779
|
-
if (!chunk || !this.active.has(source)) return;
|
|
2780
|
-
const draft = this.composer.getDraft();
|
|
2781
|
-
if (draft !== this.expected) this.last = null;
|
|
2782
|
-
const labelled = this.active.size > 1;
|
|
2783
|
-
const timestamps = this.sourceTimestamps.get(source) ?? this.timestamps;
|
|
2784
|
-
const changed = (labelled || timestamps) && this.last !== source;
|
|
2785
|
-
const date = new Date(Number.isFinite(startedAt) ? startedAt : Date.now());
|
|
2786
|
-
const pad = (value) => String(value).padStart(2, "0");
|
|
2787
|
-
const stamp = timestamps && changed ? "[" + date.getFullYear() + "/" + pad(date.getMonth() + 1) + "/" + pad(date.getDate()) + " " + pad(date.getHours()) + ":" + pad(date.getMinutes()) + ":" + pad(date.getSeconds()) + "] " : "";
|
|
2788
|
-
const prefix = changed ? stamp + (labelled ? source === "microphone" ? "Me: " : "Them: " : "") : "";
|
|
2789
|
-
const separator = draft ? changed ? "\n\n" : "\n" : "";
|
|
2790
|
-
const next = draft + separator + prefix + chunk;
|
|
2791
|
-
this.composer.setDraft(next);
|
|
2792
|
-
this.expected = next;
|
|
2793
|
-
this.last = labelled || timestamps ? source : null;
|
|
2794
|
-
}
|
|
2795
|
-
reset() {
|
|
2796
|
-
this.active.clear();
|
|
2797
|
-
this.last = null;
|
|
2798
|
-
this.expected = null;
|
|
2799
|
-
}
|
|
2800
|
-
};
|
|
2801
|
-
|
|
2802
|
-
// src/modules/core/transcript.ts
|
|
2803
|
-
var TranscriptDraft = class {
|
|
2804
|
-
reset() {
|
|
2805
|
-
}
|
|
2806
|
-
update(current, hypothesis, final = false) {
|
|
2807
|
-
if (!final || !hypothesis) return current;
|
|
2808
|
-
const separator = current && !/\s$/.test(current) ? " " : "";
|
|
2809
|
-
return current + separator + hypothesis;
|
|
2810
|
-
}
|
|
2811
|
-
};
|
|
2812
|
-
|
|
2813
3074
|
// src/modules/core/speechDefaults.ts
|
|
2814
3075
|
var notices = {
|
|
2815
3076
|
en: "You can see the code in our conversation history.",
|
|
@@ -2893,6 +3154,11 @@ var defaultSettings = Object.freeze({
|
|
|
2893
3154
|
recognitionFilterEnabled: true,
|
|
2894
3155
|
recognitionMinimumWords: 2,
|
|
2895
3156
|
voiceCommandsEnabled: true,
|
|
3157
|
+
sharedVoiceCommandsEnabled: true,
|
|
3158
|
+
timestampsEnabled: false,
|
|
3159
|
+
sharedTimestampsEnabled: false,
|
|
3160
|
+
microphoneSourceName: "Me",
|
|
3161
|
+
sharedSourceName: "Them",
|
|
2896
3162
|
voiceCommandSend: "send, send message",
|
|
2897
3163
|
voiceCommandQueue: "queue, queue message",
|
|
2898
3164
|
voiceCommandEnd: "end, end conversation",
|
|
@@ -2904,8 +3170,15 @@ var defaultSettings = Object.freeze({
|
|
|
2904
3170
|
outputCodeMaxLines: 5,
|
|
2905
3171
|
outputCodeNotice: resolveCodeNotice(void 0, "pt-BR"),
|
|
2906
3172
|
rate: 1,
|
|
3173
|
+
volume: 1,
|
|
2907
3174
|
segmentGapMs: 400
|
|
2908
3175
|
});
|
|
3176
|
+
var normalizeSourceName = (value, fallback) => {
|
|
3177
|
+
if (typeof value !== "string" || /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/u.test(value))
|
|
3178
|
+
return fallback;
|
|
3179
|
+
const name = value.trim();
|
|
3180
|
+
return name && name.length <= 80 ? name : fallback;
|
|
3181
|
+
};
|
|
2909
3182
|
var normalizeCommandPhrases = (value, fallback) => typeof value === "string" && value.length <= 1e3 && !value.includes("\0") ? value.split(/[,\r\n]+/).map((phrase) => phrase.trim()).filter(Boolean).slice(0, 20).join(", ") : fallback;
|
|
2910
3183
|
var customSilenceMinMs = 100;
|
|
2911
3184
|
var customSilenceMaxMs = 1e4;
|
|
@@ -2941,6 +3214,17 @@ function normalizeSettings(value) {
|
|
|
2941
3214
|
recognitionFilterEnabled: typeof source.recognitionFilterEnabled === "boolean" ? source.recognitionFilterEnabled : defaultSettings.recognitionFilterEnabled,
|
|
2942
3215
|
recognitionMinimumWords: Number.isInteger(source.recognitionMinimumWords) && source.recognitionMinimumWords >= 1 && source.recognitionMinimumWords <= 20 ? source.recognitionMinimumWords : defaultSettings.recognitionMinimumWords,
|
|
2943
3216
|
voiceCommandsEnabled: typeof source.voiceCommandsEnabled === "boolean" ? source.voiceCommandsEnabled : defaultSettings.voiceCommandsEnabled,
|
|
3217
|
+
microphoneSourceName: normalizeSourceName(
|
|
3218
|
+
source.microphoneSourceName,
|
|
3219
|
+
defaultSettings.microphoneSourceName
|
|
3220
|
+
),
|
|
3221
|
+
sharedSourceName: normalizeSourceName(
|
|
3222
|
+
source.sharedSourceName,
|
|
3223
|
+
defaultSettings.sharedSourceName
|
|
3224
|
+
),
|
|
3225
|
+
timestampsEnabled: typeof source.timestampsEnabled === "boolean" ? source.timestampsEnabled : false,
|
|
3226
|
+
sharedTimestampsEnabled: typeof source.sharedTimestampsEnabled === "boolean" ? source.sharedTimestampsEnabled : false,
|
|
3227
|
+
sharedVoiceCommandsEnabled: typeof source.sharedVoiceCommandsEnabled === "boolean" ? source.sharedVoiceCommandsEnabled : typeof source.voiceCommandsEnabled === "boolean" ? source.voiceCommandsEnabled : defaultSettings.sharedVoiceCommandsEnabled,
|
|
2944
3228
|
voiceCommandSend: normalizeCommandPhrases(
|
|
2945
3229
|
source.voiceCommandSend,
|
|
2946
3230
|
defaultSettings.voiceCommandSend
|
|
@@ -2973,10 +3257,79 @@ function normalizeSettings(value) {
|
|
|
2973
3257
|
outputCodeMaxLines: Number.isInteger(source.outputCodeMaxLines) && source.outputCodeMaxLines >= 0 && source.outputCodeMaxLines <= 100 ? source.outputCodeMaxLines : defaultSettings.outputCodeMaxLines,
|
|
2974
3258
|
outputCodeNotice: typeof source.outputCodeNotice === "string" && source.outputCodeNotice.trim() && source.outputCodeNotice.length <= 300 && !source.outputCodeNotice.includes("\0") ? resolveCodeNotice(source.outputCodeNotice, source.lang || defaultSettings.lang) : resolveCodeNotice(defaultSettings.outputCodeNotice, source.lang || defaultSettings.lang),
|
|
2975
3259
|
rate: Number.isFinite(source.rate) && source.rate >= 0.1 && source.rate <= 3 ? source.rate : 1,
|
|
3260
|
+
volume: Number.isFinite(source.volume) && source.volume >= 0 && source.volume <= 1 ? source.volume : 1,
|
|
2976
3261
|
segmentGapMs: Number.isFinite(source.segmentGapMs) && source.segmentGapMs >= 0 && source.segmentGapMs <= 2e3 ? Math.round(source.segmentGapMs) : 400
|
|
2977
3262
|
};
|
|
2978
3263
|
}
|
|
2979
3264
|
|
|
3265
|
+
// src/modules/conversation/models/meetingTranscript.ts
|
|
3266
|
+
var MeetingTranscript = class {
|
|
3267
|
+
constructor(composer, settings = () => defaultSettings) {
|
|
3268
|
+
this.composer = composer;
|
|
3269
|
+
this.settings = settings;
|
|
3270
|
+
}
|
|
3271
|
+
composer;
|
|
3272
|
+
settings;
|
|
3273
|
+
active = /* @__PURE__ */ new Set();
|
|
3274
|
+
last = null;
|
|
3275
|
+
expected = null;
|
|
3276
|
+
timestamps = false;
|
|
3277
|
+
sourceTimestamps = /* @__PURE__ */ new Map();
|
|
3278
|
+
setSourceTimestamps(source, enabled) {
|
|
3279
|
+
if (this.sourceTimestamps.get(source) === enabled) return;
|
|
3280
|
+
this.sourceTimestamps.set(source, enabled);
|
|
3281
|
+
this.last = null;
|
|
3282
|
+
}
|
|
3283
|
+
setTimestamps(enabled) {
|
|
3284
|
+
this.timestamps = enabled;
|
|
3285
|
+
this.last = null;
|
|
3286
|
+
}
|
|
3287
|
+
setActive(source, enabled) {
|
|
3288
|
+
if (enabled) this.active.add(source);
|
|
3289
|
+
else this.active.delete(source);
|
|
3290
|
+
this.last = null;
|
|
3291
|
+
}
|
|
3292
|
+
append(source, text, startedAt) {
|
|
3293
|
+
const chunk = text.trim();
|
|
3294
|
+
if (!chunk || !this.active.has(source)) return;
|
|
3295
|
+
const draft = this.composer.getDraft();
|
|
3296
|
+
if (draft !== this.expected) this.last = null;
|
|
3297
|
+
const labelled = this.active.size > 1;
|
|
3298
|
+
const timestamps = this.sourceTimestamps.get(source) ?? this.timestamps;
|
|
3299
|
+
const changed = (labelled || timestamps) && this.last !== source;
|
|
3300
|
+
const date = new Date(Number.isFinite(startedAt) ? startedAt : Date.now());
|
|
3301
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
3302
|
+
const stamp = timestamps && changed ? "[" + date.getFullYear() + "/" + pad(date.getMonth() + 1) + "/" + pad(date.getDate()) + " " + pad(date.getHours()) + ":" + pad(date.getMinutes()) + ":" + pad(date.getSeconds()) + "] " : "";
|
|
3303
|
+
const key = source === "microphone" ? "microphoneSourceName" : "sharedSourceName";
|
|
3304
|
+
const name = normalizeSourceName(this.settings()[key], defaultSettings[key]);
|
|
3305
|
+
const prefix = changed ? stamp + (labelled ? name + ": " : "") : "";
|
|
3306
|
+
const separator = draft ? changed ? "\n\n" : "\n" : "";
|
|
3307
|
+
const next = draft + separator + prefix + chunk;
|
|
3308
|
+
this.composer.setDraft(next);
|
|
3309
|
+
this.expected = next;
|
|
3310
|
+
this.last = labelled || timestamps ? source : null;
|
|
3311
|
+
}
|
|
3312
|
+
reset() {
|
|
3313
|
+
this.active.clear();
|
|
3314
|
+
this.last = null;
|
|
3315
|
+
this.expected = null;
|
|
3316
|
+
}
|
|
3317
|
+
};
|
|
3318
|
+
|
|
3319
|
+
// src/modules/core/transcript.ts
|
|
3320
|
+
var TranscriptDraft = class {
|
|
3321
|
+
reset() {
|
|
3322
|
+
}
|
|
3323
|
+
update(current, hypothesis, final = false) {
|
|
3324
|
+
if (!final || !hypothesis) return current;
|
|
3325
|
+
const separator = current && !/\s$/.test(current) ? " " : "";
|
|
3326
|
+
return current + separator + hypothesis;
|
|
3327
|
+
}
|
|
3328
|
+
};
|
|
3329
|
+
|
|
3330
|
+
// src/modules/speak/services/speechQueue.ts
|
|
3331
|
+
var SPEECH_QUEUE_PREFETCH_LIMIT = 3;
|
|
3332
|
+
|
|
2980
3333
|
// node_modules/.pnpm/marked@18.1.0/node_modules/marked/lib/marked.esm.js
|
|
2981
3334
|
function I() {
|
|
2982
3335
|
return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
|
|
@@ -4523,7 +4876,8 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
4523
4876
|
speechHasPrevious: false,
|
|
4524
4877
|
speechRunActive: false,
|
|
4525
4878
|
capabilities: {},
|
|
4526
|
-
settings: normalizeSettings(settings)
|
|
4879
|
+
settings: normalizeSettings(settings),
|
|
4880
|
+
timestamps: normalizeSettings(settings).timestampsEnabled
|
|
4527
4881
|
};
|
|
4528
4882
|
this.autoSendTimer = null;
|
|
4529
4883
|
this.autoSendDraft = null;
|
|
@@ -4582,6 +4936,9 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
4582
4936
|
(key) => Object.hasOwn(next, key) && settings[key] !== previousSettings[key]
|
|
4583
4937
|
);
|
|
4584
4938
|
if (speechPreparationChanged) this._cancelSpeechPrefetch();
|
|
4939
|
+
if (settings.volume !== previousSettings.volume) {
|
|
4940
|
+
this.engines[this.snapshot.speechEngine || settings.engine]?.setVolume?.(settings.volume);
|
|
4941
|
+
}
|
|
4585
4942
|
this.meter.deviceId = settings.inputDeviceId;
|
|
4586
4943
|
Object.assign(this.recognition, {
|
|
4587
4944
|
lang: settings.recognitionLang,
|
|
@@ -4593,16 +4950,14 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
4593
4950
|
});
|
|
4594
4951
|
this.patch({
|
|
4595
4952
|
settings,
|
|
4953
|
+
timestamps: settings.timestampsEnabled,
|
|
4596
4954
|
muted: settings.microphoneEnabled === false,
|
|
4597
4955
|
recognizing: this.snapshot.recognizing,
|
|
4598
4956
|
error: null
|
|
4599
4957
|
});
|
|
4600
4958
|
if (settings.sendingMode === "manual") this.cancelAutoSend();
|
|
4601
|
-
if (
|
|
4602
|
-
this.
|
|
4603
|
-
this.queue = [];
|
|
4604
|
-
this.assistantSpeechNotBefore = 0;
|
|
4605
|
-
this._cancelAssistantSpeechTimer();
|
|
4959
|
+
if (previousSettings.announceAssistantMessages && !settings.announceAssistantMessages) {
|
|
4960
|
+
void this.stopSpeech();
|
|
4606
4961
|
}
|
|
4607
4962
|
if (Object.hasOwn(next, "assistantSpeechDelaySeconds") && this.assistantSpeechNotBefore > 0) {
|
|
4608
4963
|
this.assistantSpeechNotBefore = Date.now() + settings.assistantSpeechDelaySeconds * 1e3;
|
|
@@ -4610,7 +4965,35 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
4610
4965
|
this._drain();
|
|
4611
4966
|
}
|
|
4612
4967
|
}
|
|
4613
|
-
async refreshCapabilities() {
|
|
4968
|
+
async refreshCapabilities({ localOnly = false } = {}) {
|
|
4969
|
+
if (localOnly) {
|
|
4970
|
+
const playback = Object.fromEntries(
|
|
4971
|
+
Object.entries(this.engines).map(([id2, engine]) => [
|
|
4972
|
+
id2,
|
|
4973
|
+
{
|
|
4974
|
+
...this.snapshot.capabilities[id2],
|
|
4975
|
+
...engine.getPlaybackCapabilities?.()
|
|
4976
|
+
}
|
|
4977
|
+
])
|
|
4978
|
+
);
|
|
4979
|
+
const browser = this.engines.browser?.voices?.();
|
|
4980
|
+
const capture = await this.meter.capability?.();
|
|
4981
|
+
if (this.disposed) return;
|
|
4982
|
+
this.patch({
|
|
4983
|
+
capabilities: {
|
|
4984
|
+
...this.snapshot.capabilities,
|
|
4985
|
+
...playback,
|
|
4986
|
+
...browser ? {
|
|
4987
|
+
browser: {
|
|
4988
|
+
...playback.browser,
|
|
4989
|
+
voices: browser.map(({ name, voiceURI, lang: lang2 }) => ({ name, voiceURI, lang: lang2 }))
|
|
4990
|
+
}
|
|
4991
|
+
} : {},
|
|
4992
|
+
...capture ? { capture } : {}
|
|
4993
|
+
}
|
|
4994
|
+
});
|
|
4995
|
+
return;
|
|
4996
|
+
}
|
|
4614
4997
|
const request = this.capabilityRequest = (this.capabilityRequest || 0) + 1;
|
|
4615
4998
|
const caps = {};
|
|
4616
4999
|
const lang = this.snapshot.settings.recognitionLang;
|
|
@@ -4696,7 +5079,7 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
4696
5079
|
this._drain();
|
|
4697
5080
|
}
|
|
4698
5081
|
toggleTimestamps() {
|
|
4699
|
-
this.
|
|
5082
|
+
return this.updateSettings({ timestampsEnabled: !this.snapshot.timestamps });
|
|
4700
5083
|
}
|
|
4701
5084
|
muteListening() {
|
|
4702
5085
|
this.cancelAutoSend();
|
|
@@ -4948,8 +5331,8 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
4948
5331
|
else if (command === "mute") this.muteListening();
|
|
4949
5332
|
else if (command === "resume") this.resumeListeningInput();
|
|
4950
5333
|
else if (command === "stopSpeaking") {
|
|
5334
|
+
if (!this.snapshot.settings.announceAssistantMessages) void this.stopSpeech();
|
|
4951
5335
|
this.updateSettings({ announceAssistantMessages: false });
|
|
4952
|
-
void this.stopSpeech();
|
|
4953
5336
|
} else if (command === "clear") {
|
|
4954
5337
|
this.cancelAutoSend();
|
|
4955
5338
|
this.transcript.reset();
|
|
@@ -5101,16 +5484,18 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5101
5484
|
item.preparationKey = key;
|
|
5102
5485
|
}
|
|
5103
5486
|
_prefetchSpeech() {
|
|
5487
|
+
if (this.speechSuspended && !this.queue[0]?.manual) return;
|
|
5104
5488
|
const engine = this.engines[this.snapshot.settings.engine];
|
|
5105
5489
|
if (typeof engine?.prepare !== "function") return;
|
|
5106
5490
|
const options = {
|
|
5107
5491
|
voice: this.snapshot.settings.voice || void 0,
|
|
5108
5492
|
rate: this.snapshot.settings.rate,
|
|
5493
|
+
volume: this.snapshot.settings.volume,
|
|
5109
5494
|
lang: this.snapshot.settings.lang,
|
|
5110
5495
|
outputDeviceId: this.snapshot.settings.outputDeviceId
|
|
5111
5496
|
};
|
|
5112
5497
|
const key = this._speechPreparationKey();
|
|
5113
|
-
for (const item of this.queue.slice(0,
|
|
5498
|
+
for (const item of this.queue.slice(0, SPEECH_QUEUE_PREFETCH_LIMIT)) {
|
|
5114
5499
|
this._resetStaleSpeechItem(item, key);
|
|
5115
5500
|
if (item.prepared || item.preparing) continue;
|
|
5116
5501
|
this.prefetchItems.add(item);
|
|
@@ -5163,6 +5548,48 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5163
5548
|
speechSegmentIndex
|
|
5164
5549
|
});
|
|
5165
5550
|
}
|
|
5551
|
+
/** Copy only logical automatic-speech state before lifecycle teardown destroys resources. */
|
|
5552
|
+
checkpointSpeech() {
|
|
5553
|
+
const active = this.snapshot.speaking && this.activeSpeechItem && !this.activeSpeechItem.manual ? [this.activeSpeechItem] : [];
|
|
5554
|
+
return {
|
|
5555
|
+
consumed: [...this.consumed],
|
|
5556
|
+
unfinished: [...this.unfinished],
|
|
5557
|
+
suppressed: [...this.suppressed],
|
|
5558
|
+
pending: [...active, ...this.queue.filter((item) => !item.manual)].map(({ text, id: id2 }) => ({
|
|
5559
|
+
text,
|
|
5560
|
+
id: id2
|
|
5561
|
+
})),
|
|
5562
|
+
paused: this.snapshot.paused && !this.interruptionPausedSpeech
|
|
5563
|
+
};
|
|
5564
|
+
}
|
|
5565
|
+
restoreSpeech(checkpoint) {
|
|
5566
|
+
if (!checkpoint || this.disposed) return;
|
|
5567
|
+
this.consumed = new Map(checkpoint.consumed);
|
|
5568
|
+
this.unfinished = new Set(checkpoint.unfinished);
|
|
5569
|
+
this.suppressed = new Set(checkpoint.suppressed);
|
|
5570
|
+
this.queue = checkpoint.pending.map(({ text, id: id2 }) => ({ text, id: id2 }));
|
|
5571
|
+
this.patch({ paused: checkpoint.paused && this.queue.length > 0 });
|
|
5572
|
+
this._syncSpeechSegments();
|
|
5573
|
+
}
|
|
5574
|
+
async suspendSpeech() {
|
|
5575
|
+
this.speechSuspended = true;
|
|
5576
|
+
await Promise.all([
|
|
5577
|
+
_VoiceCoordinator.prototype.stopSpeech.call(this, false),
|
|
5578
|
+
this.stopListening()
|
|
5579
|
+
]);
|
|
5580
|
+
}
|
|
5581
|
+
discardSpeechMessage(id2) {
|
|
5582
|
+
this.suppressed.add(id2);
|
|
5583
|
+
this.queue = this.queue.filter((item) => item.id !== id2);
|
|
5584
|
+
if (this.snapshot.activeMessageId === id2) void this._navigateSpeech();
|
|
5585
|
+
this._syncSpeechSegments();
|
|
5586
|
+
}
|
|
5587
|
+
activateSpeech() {
|
|
5588
|
+
if (this.disposed) return;
|
|
5589
|
+
this.speechSuspended = false;
|
|
5590
|
+
this._prefetchSpeech();
|
|
5591
|
+
this._drain();
|
|
5592
|
+
}
|
|
5166
5593
|
_suppressPending() {
|
|
5167
5594
|
for (const id2 of this.unfinished) this.suppressed.add(id2);
|
|
5168
5595
|
if (this.snapshot.activeMessageId !== null) this.suppressed.add(this.snapshot.activeMessageId);
|
|
@@ -5170,6 +5597,8 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5170
5597
|
this.queue = [];
|
|
5171
5598
|
}
|
|
5172
5599
|
async stopSpeech(resumeListening = true) {
|
|
5600
|
+
this._cancelAssistantSpeechTimer();
|
|
5601
|
+
this.assistantSpeechNotBefore = 0;
|
|
5173
5602
|
this._cancelInterruptionResume();
|
|
5174
5603
|
if (this.interruptionTimer !== null) clearTimeout(this.interruptionTimer);
|
|
5175
5604
|
this.interruptionTimer = null;
|
|
@@ -5178,6 +5607,8 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5178
5607
|
this.interruptionPausedSpeech = false;
|
|
5179
5608
|
const epoch = ++this.speechEpoch;
|
|
5180
5609
|
++this.controlEpoch;
|
|
5610
|
+
this.speechController?.abort();
|
|
5611
|
+
this.speechLaunchPending = false;
|
|
5181
5612
|
this._cancelSpeechPrefetch();
|
|
5182
5613
|
this._suppressPending();
|
|
5183
5614
|
this._releaseSpeechHistory();
|
|
@@ -5230,6 +5661,7 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5230
5661
|
const engine = this.engines[this.snapshot.speechEngine || this.snapshot.settings.engine];
|
|
5231
5662
|
const epoch = ++this.speechEpoch;
|
|
5232
5663
|
++this.controlEpoch;
|
|
5664
|
+
this.speechController?.abort();
|
|
5233
5665
|
this._cancelAssistantSpeechTimer();
|
|
5234
5666
|
this.assistantSpeechNotBefore = 0;
|
|
5235
5667
|
this.patch({ speaking: false, paused: false, speechLoading: false });
|
|
@@ -5262,6 +5694,11 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5262
5694
|
return;
|
|
5263
5695
|
}
|
|
5264
5696
|
if (!this.snapshot.speaking) return;
|
|
5697
|
+
if (this.speechLaunchPending) {
|
|
5698
|
+
++this.controlEpoch;
|
|
5699
|
+
this.patch({ paused: true });
|
|
5700
|
+
return;
|
|
5701
|
+
}
|
|
5265
5702
|
const epoch = this.speechEpoch;
|
|
5266
5703
|
const control = ++this.controlEpoch;
|
|
5267
5704
|
try {
|
|
@@ -5283,6 +5720,20 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5283
5720
|
this._drain();
|
|
5284
5721
|
return;
|
|
5285
5722
|
}
|
|
5723
|
+
if (this.speechLaunchPending) {
|
|
5724
|
+
const epoch2 = this.speechEpoch;
|
|
5725
|
+
const control2 = ++this.controlEpoch;
|
|
5726
|
+
if (this.snapshot.settings.mode === "speaker") {
|
|
5727
|
+
await this.stopListening();
|
|
5728
|
+
if (this.inputReleaseError) {
|
|
5729
|
+
this.patch({ error: message(this.inputReleaseError) });
|
|
5730
|
+
return;
|
|
5731
|
+
}
|
|
5732
|
+
}
|
|
5733
|
+
if (epoch2 === this.speechEpoch && control2 === this.controlEpoch)
|
|
5734
|
+
this.patch({ paused: false });
|
|
5735
|
+
return;
|
|
5736
|
+
}
|
|
5286
5737
|
const epoch = this.speechEpoch;
|
|
5287
5738
|
const control = ++this.controlEpoch;
|
|
5288
5739
|
try {
|
|
@@ -5334,6 +5785,9 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5334
5785
|
if (!this.speechHistory.includes(item)) this.speechHistory.push(item);
|
|
5335
5786
|
this.speechCursor = this.speechHistory.indexOf(item);
|
|
5336
5787
|
const epoch = ++this.speechEpoch;
|
|
5788
|
+
const controller = new AbortController();
|
|
5789
|
+
this.speechController = controller;
|
|
5790
|
+
this.speechLaunchPending = true;
|
|
5337
5791
|
const engine = this.engines[this.snapshot.settings.engine];
|
|
5338
5792
|
this._resetStaleSpeechItem(item, this._speechPreparationKey());
|
|
5339
5793
|
item.engine = engine;
|
|
@@ -5372,7 +5826,9 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5372
5826
|
},
|
|
5373
5827
|
voice: this.snapshot.settings.voice || void 0,
|
|
5374
5828
|
rate: this.snapshot.settings.rate,
|
|
5375
|
-
|
|
5829
|
+
volume: this.snapshot.settings.volume,
|
|
5830
|
+
outputDeviceId: this.snapshot.settings.outputDeviceId,
|
|
5831
|
+
signal: controller.signal
|
|
5376
5832
|
};
|
|
5377
5833
|
if (!queued.prepared && typeof engine.prepare === "function") {
|
|
5378
5834
|
const prepared = await engine.prepare(text, options);
|
|
@@ -5382,6 +5838,11 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5382
5838
|
}
|
|
5383
5839
|
queued.prepared = prepared;
|
|
5384
5840
|
}
|
|
5841
|
+
while (this.snapshot.paused && epoch === this.speechEpoch && !this.disposed)
|
|
5842
|
+
await this._waitSpeechLaunch(controller.signal);
|
|
5843
|
+
if (epoch !== this.speechEpoch || this.disposed) return;
|
|
5844
|
+
this.speechLaunchPending = false;
|
|
5845
|
+
options.volume = this.snapshot.settings.volume;
|
|
5385
5846
|
if (queued?.prepared && typeof engine.playPrepared === "function") {
|
|
5386
5847
|
const prepared = queued.prepared;
|
|
5387
5848
|
this.prefetchItems.delete(queued);
|
|
@@ -5414,12 +5875,27 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5414
5875
|
}
|
|
5415
5876
|
}
|
|
5416
5877
|
}
|
|
5417
|
-
|
|
5418
|
-
if (this.
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5878
|
+
_waitSpeechLaunch(signal) {
|
|
5879
|
+
if (!this.snapshot.paused) return Promise.resolve();
|
|
5880
|
+
return new Promise((resolve) => {
|
|
5881
|
+
const done = () => {
|
|
5882
|
+
unsubscribe();
|
|
5883
|
+
signal.removeEventListener("abort", done);
|
|
5884
|
+
resolve();
|
|
5885
|
+
};
|
|
5886
|
+
const unsubscribe = this.subscribe(() => {
|
|
5887
|
+
if (!this.snapshot.paused || signal.aborted) done();
|
|
5888
|
+
});
|
|
5889
|
+
signal.addEventListener("abort", done, { once: true });
|
|
5890
|
+
if (signal.aborted) done();
|
|
5891
|
+
});
|
|
5892
|
+
}
|
|
5893
|
+
_cancelAssistantSpeechTimer() {
|
|
5894
|
+
if (this.assistantSpeechTimer !== null) clearTimeout(this.assistantSpeechTimer);
|
|
5895
|
+
this.assistantSpeechTimer = null;
|
|
5896
|
+
}
|
|
5897
|
+
_drain() {
|
|
5898
|
+
if (this.disposed || this.speechSuspended && !this.queue[0]?.manual || !this.snapshot.settings.announceAssistantMessages && !this.queue[0]?.manual || this.snapshot.speaking || this.snapshot.paused || this._speechActivity() || this.snapshot.starting || !this.queue[0]?.manual && (this.snapshot.pendingTranscriptions > 0 || this.snapshot.autoSendAt !== null) || !this.queue.length)
|
|
5423
5899
|
return;
|
|
5424
5900
|
const wait = this.assistantSpeechNotBefore - Date.now();
|
|
5425
5901
|
if (wait > 0) {
|
|
@@ -5450,7 +5926,7 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5450
5926
|
this.patch({ speechText: null, speechEngine: null });
|
|
5451
5927
|
this._syncSpeechSegments();
|
|
5452
5928
|
}
|
|
5453
|
-
if (baseline || !this.snapshot.
|
|
5929
|
+
if (baseline || !this.snapshot.settings.announceAssistantMessages || this.suppressed.has(id2)) {
|
|
5454
5930
|
this.consumed.set(id2, text.length);
|
|
5455
5931
|
return;
|
|
5456
5932
|
}
|
|
@@ -5492,17 +5968,27 @@ var VoiceCoordinator = class _VoiceCoordinator {
|
|
|
5492
5968
|
|
|
5493
5969
|
// src/modules/conversation/models/meeting.ts
|
|
5494
5970
|
var MeetingController = class {
|
|
5495
|
-
constructor({
|
|
5971
|
+
constructor({
|
|
5972
|
+
composer,
|
|
5973
|
+
settings,
|
|
5974
|
+
createSource,
|
|
5975
|
+
translate,
|
|
5976
|
+
onActivity,
|
|
5977
|
+
onSpeech,
|
|
5978
|
+
stopSpeech,
|
|
5979
|
+
savePreferences
|
|
5980
|
+
}) {
|
|
5496
5981
|
this.composer = composer;
|
|
5497
5982
|
this.stopSpeech = stopSpeech;
|
|
5498
5983
|
this.inputs = /* @__PURE__ */ new Map();
|
|
5499
5984
|
this.inputOverrides = /* @__PURE__ */ new Map();
|
|
5500
5985
|
this.settings = settings;
|
|
5986
|
+
this.savePreferences = savePreferences;
|
|
5501
5987
|
this.createSource = createSource;
|
|
5502
5988
|
this.t = translate;
|
|
5503
5989
|
this.onActivity = onActivity;
|
|
5504
5990
|
this.onSpeech = onSpeech;
|
|
5505
|
-
this.transcript = new MeetingTranscript(composer);
|
|
5991
|
+
this.transcript = new MeetingTranscript(composer, settings);
|
|
5506
5992
|
this.jobs = /* @__PURE__ */ new Map();
|
|
5507
5993
|
this.generations = /* @__PURE__ */ new Map();
|
|
5508
5994
|
this.listeners = /* @__PURE__ */ new Set();
|
|
@@ -5541,7 +6027,14 @@ var MeetingController = class {
|
|
|
5541
6027
|
engines: {},
|
|
5542
6028
|
meter: { stop: async () => {
|
|
5543
6029
|
} },
|
|
5544
|
-
settings: {
|
|
6030
|
+
settings: {
|
|
6031
|
+
...this.settings(),
|
|
6032
|
+
microphoneEnabled: true,
|
|
6033
|
+
timestampsEnabled: source === "shared" ? this.settings().sharedTimestampsEnabled : this.settings().timestampsEnabled,
|
|
6034
|
+
...source === "shared" ? {
|
|
6035
|
+
voiceCommandsEnabled: this.settings().sharedVoiceCommandsEnabled ?? this.settings().voiceCommandsEnabled
|
|
6036
|
+
} : {}
|
|
6037
|
+
},
|
|
5545
6038
|
composer: {
|
|
5546
6039
|
getDraft: () => this.composer.getDraft(),
|
|
5547
6040
|
setDraft: (text) => this.composer.setDraft(text),
|
|
@@ -5562,6 +6055,14 @@ var MeetingController = class {
|
|
|
5562
6055
|
input.updateSettings = (next) => {
|
|
5563
6056
|
this.inputOverrides.set(source, { ...this.inputOverrides.get(source), ...next });
|
|
5564
6057
|
update(next);
|
|
6058
|
+
const patch = {};
|
|
6059
|
+
if (source === "shared" && Object.hasOwn(next, "voiceCommandsEnabled"))
|
|
6060
|
+
patch.sharedVoiceCommandsEnabled = next.voiceCommandsEnabled;
|
|
6061
|
+
if (Object.hasOwn(next, "timestampsEnabled")) {
|
|
6062
|
+
this.transcript.setSourceTimestamps(source, next.timestampsEnabled);
|
|
6063
|
+
patch[source === "shared" ? "sharedTimestampsEnabled" : "timestampsEnabled"] = next.timestampsEnabled;
|
|
6064
|
+
}
|
|
6065
|
+
if (Object.keys(patch).length) return this.savePreferences?.(input, patch);
|
|
5565
6066
|
};
|
|
5566
6067
|
input.clearError = () => this.patch(source, { error: null });
|
|
5567
6068
|
input.endConversation = () => this.stop(source);
|
|
@@ -5569,24 +6070,27 @@ var MeetingController = class {
|
|
|
5569
6070
|
const updatePolicy = input.updateSettings;
|
|
5570
6071
|
input.updateSettings = (next) => {
|
|
5571
6072
|
if (Object.hasOwn(next, "announceAssistantMessages"))
|
|
5572
|
-
this.composer.updatePlaybackSettings?.({
|
|
6073
|
+
this.composer.updatePlaybackSettings?.({
|
|
6074
|
+
announceAssistantMessages: next.announceAssistantMessages
|
|
6075
|
+
});
|
|
5573
6076
|
return updatePolicy(next);
|
|
5574
6077
|
};
|
|
5575
|
-
input.
|
|
5576
|
-
const timestamps = !input.getSnapshot().timestamps;
|
|
5577
|
-
this.transcript.setSourceTimestamps(source, timestamps);
|
|
5578
|
-
input.patch({ timestamps });
|
|
5579
|
-
};
|
|
6078
|
+
this.transcript.setSourceTimestamps(source, input.getSnapshot().timestamps);
|
|
5580
6079
|
this.inputs.set(source, input);
|
|
5581
6080
|
return input;
|
|
5582
6081
|
}
|
|
5583
6082
|
applySettings(settings) {
|
|
5584
|
-
for (const [source, input] of this.inputs)
|
|
6083
|
+
for (const [source, input] of this.inputs) {
|
|
6084
|
+
const timestamps = source === "shared" ? settings.sharedTimestampsEnabled : settings.timestampsEnabled;
|
|
6085
|
+
this.transcript.setSourceTimestamps(source, Boolean(timestamps));
|
|
5585
6086
|
VoiceCoordinator.prototype.updateSettings.call(input, {
|
|
5586
6087
|
...settings,
|
|
5587
6088
|
...this.inputOverrides.get(source),
|
|
6089
|
+
...source === "shared" && typeof settings.sharedVoiceCommandsEnabled === "boolean" ? { voiceCommandsEnabled: settings.sharedVoiceCommandsEnabled } : {},
|
|
6090
|
+
timestampsEnabled: timestamps ?? input.getSnapshot().timestamps,
|
|
5588
6091
|
microphoneEnabled: !input.getSnapshot().muted
|
|
5589
6092
|
});
|
|
6093
|
+
}
|
|
5590
6094
|
}
|
|
5591
6095
|
composerChanged(draft) {
|
|
5592
6096
|
for (const input of this.inputs.values()) input.composerChanged(draft);
|
|
@@ -5625,7 +6129,6 @@ var MeetingController = class {
|
|
|
5625
6129
|
this.patch(source, { starting: true, error: null });
|
|
5626
6130
|
try {
|
|
5627
6131
|
const settings = this.settings();
|
|
5628
|
-
if (settings.recognitionEngine === "browser") throw new Error(this.t("httpRequired"));
|
|
5629
6132
|
const { meter, engine } = this.createSource(source, settings);
|
|
5630
6133
|
const input = this.input(source);
|
|
5631
6134
|
input.meter = meter;
|
|
@@ -5635,9 +6138,15 @@ var MeetingController = class {
|
|
|
5635
6138
|
Object.assign(job, { meter, engine });
|
|
5636
6139
|
if (source === "shared") meter.provide(request);
|
|
5637
6140
|
meter.deviceId = settings.inputDeviceId;
|
|
5638
|
-
const capability = await engine.capability(
|
|
6141
|
+
const capability = await engine.capability({
|
|
6142
|
+
lang: settings.recognitionLang,
|
|
6143
|
+
signal: abort.signal
|
|
6144
|
+
});
|
|
5639
6145
|
if (!valid()) return;
|
|
5640
|
-
if (!capability.supported)
|
|
6146
|
+
if (!capability.supported)
|
|
6147
|
+
throw Object.assign(new Error(capability.reason || this.t("unavailable")), {
|
|
6148
|
+
code: capability.code
|
|
6149
|
+
});
|
|
5641
6150
|
if (!await meter.start({ signal: abort.signal })) {
|
|
5642
6151
|
if (valid()) await this.stop(source);
|
|
5643
6152
|
return;
|
|
@@ -5693,7 +6202,7 @@ var MeetingController = class {
|
|
|
5693
6202
|
} catch (error) {
|
|
5694
6203
|
if (valid()) {
|
|
5695
6204
|
this.patch(source, {
|
|
5696
|
-
error: source === "shared" && error.message === "No shared audio track was returned." ? this.t("noAudio") : error.
|
|
6205
|
+
error: source === "shared" && error.message === "No shared audio track was returned." ? this.t("noAudio") : error.code === "external-audio-unsupported" ? this.t("browserSharedUnsupported") : error.code === "browser-local-unavailable" ? this.t("browserLocalUnavailable") : this.t("failed")
|
|
5697
6206
|
});
|
|
5698
6207
|
await this.stop(source);
|
|
5699
6208
|
}
|
|
@@ -5713,7 +6222,13 @@ var MeetingController = class {
|
|
|
5713
6222
|
this.jobs.delete(source);
|
|
5714
6223
|
const input = this.inputs.get(source);
|
|
5715
6224
|
input?.cancelAutoSend();
|
|
5716
|
-
input?.patch({
|
|
6225
|
+
input?.patch({
|
|
6226
|
+
conversation: false,
|
|
6227
|
+
starting: false,
|
|
6228
|
+
listening: false,
|
|
6229
|
+
recognizing: false,
|
|
6230
|
+
pendingTranscriptions: 0
|
|
6231
|
+
});
|
|
5717
6232
|
this.onActivity?.(source, false);
|
|
5718
6233
|
job?.abort.abort();
|
|
5719
6234
|
this.transcript.setActive(source, false);
|
|
@@ -5979,13 +6494,13 @@ var SharedAudioMeter = class extends MicrophoneMeter {
|
|
|
5979
6494
|
};
|
|
5980
6495
|
|
|
5981
6496
|
// src/modules/conversation/components/MeetingControls.tsx
|
|
5982
|
-
var
|
|
6497
|
+
var import_react31 = __toESM(require("react"), 1);
|
|
5983
6498
|
|
|
5984
6499
|
// src/modules/conversation/components/ConversationStatusBar.tsx
|
|
5985
|
-
var
|
|
6500
|
+
var import_react30 = __toESM(require("react"), 1);
|
|
5986
6501
|
|
|
5987
6502
|
// src/modules/conversation/components/DeliveryModeButton.tsx
|
|
5988
|
-
var
|
|
6503
|
+
var import_react27 = __toESM(require("react"), 1);
|
|
5989
6504
|
function nextDeliveryMode(mode) {
|
|
5990
6505
|
return mode === "queue" ? "steer" : mode === "steer" ? "manual" : "queue";
|
|
5991
6506
|
}
|
|
@@ -5998,7 +6513,7 @@ function DeliveryModeButton({
|
|
|
5998
6513
|
const description = mode === "steer" ? settings.delivery.steerDescription() : mode === "queue" ? commons.queue() : commons.manual();
|
|
5999
6514
|
const status = settings.delivery.status({ mode: description });
|
|
6000
6515
|
const visible = mode === "steer" ? commons.send() : mode === "queue" ? commons.delivery.queueBadge() : commons.toggle.offBadge();
|
|
6001
|
-
return /* @__PURE__ */
|
|
6516
|
+
return /* @__PURE__ */ import_react27.default.createElement(
|
|
6002
6517
|
ToggleButton,
|
|
6003
6518
|
{
|
|
6004
6519
|
className: "dlv-live-toggle",
|
|
@@ -6014,15 +6529,15 @@ function DeliveryModeButton({
|
|
|
6014
6529
|
}
|
|
6015
6530
|
|
|
6016
6531
|
// src/modules/conversation/components/RecognitionBar.tsx
|
|
6017
|
-
var
|
|
6532
|
+
var import_react29 = __toESM(require("react"), 1);
|
|
6018
6533
|
|
|
6019
6534
|
// src/modules/conversation/components/Waveform.tsx
|
|
6020
|
-
var
|
|
6535
|
+
var import_react28 = __toESM(require("react"), 1);
|
|
6021
6536
|
function Waveform({ controller, enabled }) {
|
|
6022
|
-
const ref =
|
|
6023
|
-
const current =
|
|
6537
|
+
const ref = import_react28.default.useRef(null);
|
|
6538
|
+
const current = import_react28.default.useRef({ controller, enabled });
|
|
6024
6539
|
current.current = { controller, enabled };
|
|
6025
|
-
|
|
6540
|
+
import_react28.default.useEffect(() => {
|
|
6026
6541
|
const canvas = ref.current;
|
|
6027
6542
|
const context = canvas?.getContext("2d");
|
|
6028
6543
|
if (!canvas || !context) return;
|
|
@@ -6077,12 +6592,12 @@ function Waveform({ controller, enabled }) {
|
|
|
6077
6592
|
window.removeEventListener("resize", resize);
|
|
6078
6593
|
};
|
|
6079
6594
|
}, []);
|
|
6080
|
-
return /* @__PURE__ */
|
|
6595
|
+
return /* @__PURE__ */ import_react28.default.createElement("canvas", { ref, className: "dlv-wave", "aria-hidden": true });
|
|
6081
6596
|
}
|
|
6082
6597
|
|
|
6083
6598
|
// src/modules/conversation/components/RecognitionBar.tsx
|
|
6084
6599
|
function RecognitionBar({ controller, listening, label, status, leading, children }) {
|
|
6085
|
-
return /* @__PURE__ */
|
|
6600
|
+
return /* @__PURE__ */ import_react29.default.createElement("div", { className: "dlv-pill", role: "group", "aria-label": label }, leading, /* @__PURE__ */ import_react29.default.createElement(Waveform, { controller, enabled: Boolean(listening) }), /* @__PURE__ */ import_react29.default.createElement("span", { className: "dlv-status", role: "status", "aria-live": "polite" }, status), children);
|
|
6086
6601
|
}
|
|
6087
6602
|
|
|
6088
6603
|
// src/modules/conversation/components/conversationStatus.ts
|
|
@@ -6115,8 +6630,8 @@ function ConversationStatusBar({
|
|
|
6115
6630
|
const { scoped: meeting } = useLanguage((ctx) => ctx.meeting);
|
|
6116
6631
|
const state = useConversationController(controller);
|
|
6117
6632
|
const { invoke, error, clearError } = useConversationActions(controller);
|
|
6118
|
-
const [now, setNow] =
|
|
6119
|
-
|
|
6633
|
+
const [now, setNow] = import_react30.default.useState(Date.now());
|
|
6634
|
+
import_react30.default.useEffect(() => {
|
|
6120
6635
|
if (!state.autoSendAt) return;
|
|
6121
6636
|
setNow(Date.now());
|
|
6122
6637
|
const timer = setInterval(() => setNow(Date.now()), 200);
|
|
@@ -6133,28 +6648,28 @@ function ConversationStatusBar({
|
|
|
6133
6648
|
settings,
|
|
6134
6649
|
speak
|
|
6135
6650
|
});
|
|
6136
|
-
return /* @__PURE__ */
|
|
6651
|
+
return /* @__PURE__ */ import_react30.default.createElement(
|
|
6137
6652
|
"div",
|
|
6138
6653
|
{
|
|
6139
6654
|
className: overlay ? "dlv-bar-wrap dlv-bar-stack dlv-question-overlay" : "dlv-bar-wrap dlv-bar-stack",
|
|
6140
6655
|
style: overlay ? overlayStyle : void 0
|
|
6141
6656
|
},
|
|
6142
|
-
includeSpeech && /* @__PURE__ */
|
|
6143
|
-
(state.conversation || capture || state.error || error) && /* @__PURE__ */
|
|
6657
|
+
includeSpeech && /* @__PURE__ */ import_react30.default.createElement(SpeechStatusBar, { controller }),
|
|
6658
|
+
(state.conversation || capture || state.error || error) && /* @__PURE__ */ import_react30.default.createElement(
|
|
6144
6659
|
RecognitionBar,
|
|
6145
6660
|
{
|
|
6146
6661
|
controller,
|
|
6147
6662
|
listening: state.listening,
|
|
6148
6663
|
label: sourceLabel || commons.controls.title(),
|
|
6149
6664
|
status,
|
|
6150
|
-
leading: /* @__PURE__ */
|
|
6665
|
+
leading: /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, state.conversation && !capture ? /* @__PURE__ */ import_react30.default.createElement(
|
|
6151
6666
|
IconButton,
|
|
6152
6667
|
{
|
|
6153
6668
|
label: recognition.microphone.takeControl(),
|
|
6154
6669
|
icon: sourceIcon,
|
|
6155
6670
|
onClick: () => invoke("takeMicrophone")
|
|
6156
6671
|
}
|
|
6157
|
-
) : null, capture ? /* @__PURE__ */
|
|
6672
|
+
) : null, capture ? /* @__PURE__ */ import_react30.default.createElement(
|
|
6158
6673
|
ToggleButton,
|
|
6159
6674
|
{
|
|
6160
6675
|
className: "dlv-mic-state",
|
|
@@ -6170,7 +6685,7 @@ function ConversationStatusBar({
|
|
|
6170
6685
|
}
|
|
6171
6686
|
) : null)
|
|
6172
6687
|
},
|
|
6173
|
-
/* @__PURE__ */
|
|
6688
|
+
/* @__PURE__ */ import_react30.default.createElement(
|
|
6174
6689
|
ToggleButton,
|
|
6175
6690
|
{
|
|
6176
6691
|
icon: "filter",
|
|
@@ -6180,7 +6695,7 @@ function ConversationStatusBar({
|
|
|
6180
6695
|
onClick: () => invoke("updateSettings", { voiceCommandsEnabled: !state.settings.voiceCommandsEnabled })
|
|
6181
6696
|
}
|
|
6182
6697
|
),
|
|
6183
|
-
/* @__PURE__ */
|
|
6698
|
+
/* @__PURE__ */ import_react30.default.createElement(
|
|
6184
6699
|
ToggleButton,
|
|
6185
6700
|
{
|
|
6186
6701
|
className: "dlv-timestamp-toggle",
|
|
@@ -6191,14 +6706,14 @@ function ConversationStatusBar({
|
|
|
6191
6706
|
onClick: () => invoke("toggleTimestamps")
|
|
6192
6707
|
}
|
|
6193
6708
|
),
|
|
6194
|
-
/* @__PURE__ */
|
|
6709
|
+
/* @__PURE__ */ import_react30.default.createElement(
|
|
6195
6710
|
DeliveryModeButton,
|
|
6196
6711
|
{
|
|
6197
6712
|
mode: state.settings.sendingMode || "manual",
|
|
6198
6713
|
onChange: (sendingMode) => invoke("updateSettings", { sendingMode })
|
|
6199
6714
|
}
|
|
6200
6715
|
),
|
|
6201
|
-
remaining ? /* @__PURE__ */
|
|
6716
|
+
remaining ? /* @__PURE__ */ import_react30.default.createElement(
|
|
6202
6717
|
IconButton,
|
|
6203
6718
|
{
|
|
6204
6719
|
label: settings.autoSend.cancel(),
|
|
@@ -6207,7 +6722,7 @@ function ConversationStatusBar({
|
|
|
6207
6722
|
}
|
|
6208
6723
|
) : null
|
|
6209
6724
|
),
|
|
6210
|
-
/* @__PURE__ */
|
|
6725
|
+
/* @__PURE__ */ import_react30.default.createElement(
|
|
6211
6726
|
ErrorMessage,
|
|
6212
6727
|
{
|
|
6213
6728
|
error: error || state.error,
|
|
@@ -6225,9 +6740,9 @@ function ConversationStatusBar({
|
|
|
6225
6740
|
// src/modules/conversation/components/MeetingControls.tsx
|
|
6226
6741
|
function MeetingToggle({ meeting, onToggle }) {
|
|
6227
6742
|
const { scoped: copy } = useLanguage((ctx) => ctx.meeting);
|
|
6228
|
-
const state =
|
|
6743
|
+
const state = import_react31.default.useSyncExternalStore(meeting.subscribe, meeting.getSnapshot);
|
|
6229
6744
|
const active = Boolean(state.shared.listening || state.shared.starting);
|
|
6230
|
-
return /* @__PURE__ */
|
|
6745
|
+
return /* @__PURE__ */ import_react31.default.createElement(
|
|
6231
6746
|
IconButton,
|
|
6232
6747
|
{
|
|
6233
6748
|
icon: active ? "meeting" : "meetingOff",
|
|
@@ -6242,12 +6757,12 @@ function MeetingToggle({ meeting, onToggle }) {
|
|
|
6242
6757
|
}
|
|
6243
6758
|
function MeetingBars({ meeting }) {
|
|
6244
6759
|
const { scoped: copy } = useLanguage((ctx) => ctx.meeting);
|
|
6245
|
-
const state =
|
|
6760
|
+
const state = import_react31.default.useSyncExternalStore(meeting.subscribe, meeting.getSnapshot);
|
|
6246
6761
|
const value = state.shared;
|
|
6247
6762
|
if (!value.listening && !value.starting && !value.error) return null;
|
|
6248
6763
|
const label = copy.shared();
|
|
6249
6764
|
const input = meeting.input("shared");
|
|
6250
|
-
return /* @__PURE__ */
|
|
6765
|
+
return /* @__PURE__ */ import_react31.default.createElement("div", { className: "dlv-meeting-bars" }, /* @__PURE__ */ import_react31.default.createElement(
|
|
6251
6766
|
ConversationStatusBar,
|
|
6252
6767
|
{
|
|
6253
6768
|
controller: input,
|
|
@@ -6366,9 +6881,72 @@ var VoiceOwnership = class {
|
|
|
6366
6881
|
};
|
|
6367
6882
|
|
|
6368
6883
|
// src/modules/recognition/components/RecognitionCapabilityStatus.tsx
|
|
6369
|
-
var
|
|
6884
|
+
var import_react32 = __toESM(require("react"), 1);
|
|
6885
|
+
|
|
6886
|
+
// src/modules/recognition/engines/browser/externalAudioSupport.ts
|
|
6887
|
+
async function detectExternalAudioSupport(globals = globalThis, { signal } = {}) {
|
|
6888
|
+
let frame, stream, recognition, timer, onAbort;
|
|
6889
|
+
const clearTimer = globals.clearTimeout ?? globalThis.clearTimeout;
|
|
6890
|
+
try {
|
|
6891
|
+
if (signal?.aborted) return false;
|
|
6892
|
+
const document2 = globals.document;
|
|
6893
|
+
if (!document2?.body) return false;
|
|
6894
|
+
frame = document2.createElement("iframe");
|
|
6895
|
+
frame.hidden = true;
|
|
6896
|
+
frame.allow = "microphone 'none'";
|
|
6897
|
+
frame.srcdoc = "<!doctype html><html></html>";
|
|
6898
|
+
const loaded = await new Promise((resolve) => {
|
|
6899
|
+
frame.onload = () => resolve(true);
|
|
6900
|
+
frame.onerror = () => resolve(false);
|
|
6901
|
+
onAbort = () => resolve(false);
|
|
6902
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
6903
|
+
timer = (globals.setTimeout ?? globalThis.setTimeout)(() => resolve(false), 3e3);
|
|
6904
|
+
document2.body.append(frame);
|
|
6905
|
+
});
|
|
6906
|
+
if (!loaded || signal?.aborted || !frame.isConnected) return false;
|
|
6907
|
+
const doc = frame.contentDocument;
|
|
6908
|
+
const window2 = frame.contentWindow;
|
|
6909
|
+
const policy = doc?.permissionsPolicy ?? doc?.featurePolicy;
|
|
6910
|
+
if (!policy?.features?.().includes("microphone") || policy.allowsFeature("microphone") !== false)
|
|
6911
|
+
return false;
|
|
6912
|
+
const Recognition = typeof globals.SpeechRecognition === "function" ? window2?.SpeechRecognition : window2?.webkitSpeechRecognition;
|
|
6913
|
+
if (typeof Recognition !== "function") return false;
|
|
6914
|
+
stream = doc.createElement("canvas").captureStream();
|
|
6915
|
+
const track = stream.getVideoTracks()[0];
|
|
6916
|
+
if (!track || track.kind !== "video") return false;
|
|
6917
|
+
track.stop();
|
|
6918
|
+
if (track.readyState !== "ended") return false;
|
|
6919
|
+
recognition = new Recognition();
|
|
6920
|
+
if (typeof recognition.start !== "function" || typeof recognition.abort !== "function")
|
|
6921
|
+
return false;
|
|
6922
|
+
try {
|
|
6923
|
+
recognition.start(track);
|
|
6924
|
+
return false;
|
|
6925
|
+
} catch (error) {
|
|
6926
|
+
return error?.name === "InvalidStateError" && frame.isConnected && !signal?.aborted;
|
|
6927
|
+
} finally {
|
|
6928
|
+
recognition.abort();
|
|
6929
|
+
}
|
|
6930
|
+
} catch {
|
|
6931
|
+
return false;
|
|
6932
|
+
} finally {
|
|
6933
|
+
if (timer !== void 0) clearTimer(timer);
|
|
6934
|
+
signal?.removeEventListener("abort", onAbort);
|
|
6935
|
+
if (frame) {
|
|
6936
|
+
frame.onload = null;
|
|
6937
|
+
frame.onerror = null;
|
|
6938
|
+
}
|
|
6939
|
+
for (const track of stream?.getTracks() ?? []) track.stop();
|
|
6940
|
+
frame?.remove();
|
|
6941
|
+
}
|
|
6942
|
+
}
|
|
6370
6943
|
|
|
6371
6944
|
// src/modules/recognition/engines/browser/BrowserRecognitionEngine.ts
|
|
6945
|
+
var externalAudioReason = "This browser cannot safely recognize shared audio. Choose Qwen or Whisper HTTP for shared audio.";
|
|
6946
|
+
var invalidAudioTrack = () => Object.assign(new Error("Shared recognition requires a live audio track."), {
|
|
6947
|
+
name: "InvalidStateError",
|
|
6948
|
+
code: "invalid-audio-track"
|
|
6949
|
+
});
|
|
6372
6950
|
var abortError = () => Object.assign(new Error("Speech recognition was cancelled."), { name: "AbortError" });
|
|
6373
6951
|
var localReason = "Local browser speech recognition is unavailable for this language. Install the local language pack, or explicitly turn off local-only processing in Settings if you permit the browser recognition service to process audio.";
|
|
6374
6952
|
var notify = (callback, value) => {
|
|
@@ -6380,6 +6958,8 @@ var notify = (callback, value) => {
|
|
|
6380
6958
|
var BrowserRecognitionEngine = class {
|
|
6381
6959
|
constructor({
|
|
6382
6960
|
globals = globalThis,
|
|
6961
|
+
meter,
|
|
6962
|
+
inputSource = "microphone",
|
|
6383
6963
|
lang = "pt-BR",
|
|
6384
6964
|
processLocally = true,
|
|
6385
6965
|
autoInstallLocalPack = true,
|
|
@@ -6395,6 +6975,8 @@ var BrowserRecognitionEngine = class {
|
|
|
6395
6975
|
throw new RangeError("restartDelayMs must be nonnegative.");
|
|
6396
6976
|
Object.assign(this, {
|
|
6397
6977
|
globals,
|
|
6978
|
+
meter,
|
|
6979
|
+
inputSource,
|
|
6398
6980
|
lang,
|
|
6399
6981
|
processLocally,
|
|
6400
6982
|
autoInstallLocalPack,
|
|
@@ -6417,7 +6999,27 @@ var BrowserRecognitionEngine = class {
|
|
|
6417
6999
|
return void 0;
|
|
6418
7000
|
}
|
|
6419
7001
|
}
|
|
6420
|
-
async capability({ lang = this.lang, processLocally = this.processLocally } = {}) {
|
|
7002
|
+
async capability({ lang = this.lang, processLocally = this.processLocally, signal } = {}) {
|
|
7003
|
+
if (this.inputSource !== "shared") return this._processingCapability({ lang, processLocally });
|
|
7004
|
+
const Recognition = this.Recognition;
|
|
7005
|
+
const externalAudio = Recognition && this.externalAudioRecognition === Recognition || await detectExternalAudioSupport(this.globals, { signal });
|
|
7006
|
+
if (!externalAudio)
|
|
7007
|
+
return {
|
|
7008
|
+
supported: false,
|
|
7009
|
+
local: processLocally,
|
|
7010
|
+
externalAudio: false,
|
|
7011
|
+
code: "external-audio-unsupported",
|
|
7012
|
+
reason: externalAudioReason
|
|
7013
|
+
};
|
|
7014
|
+
this.externalAudioRecognition = Recognition;
|
|
7015
|
+
const capability = await this._processingCapability({ lang, processLocally });
|
|
7016
|
+
return {
|
|
7017
|
+
...capability,
|
|
7018
|
+
externalAudio: true,
|
|
7019
|
+
...!capability.supported && processLocally ? { code: "browser-local-unavailable" } : {}
|
|
7020
|
+
};
|
|
7021
|
+
}
|
|
7022
|
+
async _processingCapability({ lang, processLocally }) {
|
|
6421
7023
|
try {
|
|
6422
7024
|
const Recognition = this.Recognition;
|
|
6423
7025
|
if (typeof Recognition !== "function") throw new Error();
|
|
@@ -6482,6 +7084,8 @@ var BrowserRecognitionEngine = class {
|
|
|
6482
7084
|
const session = {
|
|
6483
7085
|
lang,
|
|
6484
7086
|
signal,
|
|
7087
|
+
probeAbort: new AbortController(),
|
|
7088
|
+
audioTrack: null,
|
|
6485
7089
|
onResult,
|
|
6486
7090
|
onActivity,
|
|
6487
7091
|
onError,
|
|
@@ -6502,7 +7106,11 @@ var BrowserRecognitionEngine = class {
|
|
|
6502
7106
|
};
|
|
6503
7107
|
signal?.addEventListener("abort", session.cancel, { once: true });
|
|
6504
7108
|
const capability = await Promise.race([
|
|
6505
|
-
this.capability({
|
|
7109
|
+
this.capability({
|
|
7110
|
+
lang,
|
|
7111
|
+
processLocally: this.processLocally,
|
|
7112
|
+
signal: session.probeAbort.signal
|
|
7113
|
+
}),
|
|
6506
7114
|
cancelled3
|
|
6507
7115
|
]);
|
|
6508
7116
|
if (this.session !== session || signal?.aborted) {
|
|
@@ -6511,9 +7119,11 @@ var BrowserRecognitionEngine = class {
|
|
|
6511
7119
|
}
|
|
6512
7120
|
if (!capability.supported) {
|
|
6513
7121
|
this.stop();
|
|
6514
|
-
throw new Error(capability.reason);
|
|
7122
|
+
throw Object.assign(new Error(capability.reason), { code: capability.code });
|
|
6515
7123
|
}
|
|
6516
7124
|
try {
|
|
7125
|
+
if (this.inputSource === "shared")
|
|
7126
|
+
session.audioTrack = this.meter?.stream?.getAudioTracks?.()[0];
|
|
6517
7127
|
this._begin(session);
|
|
6518
7128
|
if (this.session !== session) throw abortError();
|
|
6519
7129
|
} catch (error) {
|
|
@@ -6538,6 +7148,8 @@ var BrowserRecognitionEngine = class {
|
|
|
6538
7148
|
}
|
|
6539
7149
|
_begin(session) {
|
|
6540
7150
|
if (this.session !== session) return;
|
|
7151
|
+
if (this.inputSource === "shared" && (session.audioTrack?.kind !== "audio" || session.audioTrack.readyState !== "live"))
|
|
7152
|
+
throw invalidAudioTrack();
|
|
6541
7153
|
const recognition = new this.Recognition();
|
|
6542
7154
|
if (this.processLocally) {
|
|
6543
7155
|
if (!("processLocally" in recognition)) throw new Error(localReason);
|
|
@@ -6628,7 +7240,8 @@ var BrowserRecognitionEngine = class {
|
|
|
6628
7240
|
Math.min(3e4, this.restartDelayMs * 2 ** Math.min(session.restarts - 1, 20))
|
|
6629
7241
|
);
|
|
6630
7242
|
};
|
|
6631
|
-
recognition.start();
|
|
7243
|
+
if (this.inputSource === "shared") recognition.start(session.audioTrack);
|
|
7244
|
+
else recognition.start();
|
|
6632
7245
|
}
|
|
6633
7246
|
finish() {
|
|
6634
7247
|
const session = this.session;
|
|
@@ -6682,6 +7295,7 @@ var BrowserRecognitionEngine = class {
|
|
|
6682
7295
|
if (!session) return;
|
|
6683
7296
|
this.session = null;
|
|
6684
7297
|
session.rejectCancelled(abortError());
|
|
7298
|
+
session.probeAbort.abort();
|
|
6685
7299
|
session.signal?.removeEventListener("abort", session.cancel);
|
|
6686
7300
|
if (session.timer !== null)
|
|
6687
7301
|
(this.globals.clearTimeout ?? globalThis.clearTimeout)(session.timer);
|
|
@@ -7084,6 +7698,9 @@ var HostAudioSpeakingEngine = class {
|
|
|
7084
7698
|
this.playbackRate = playbackRate || ((rate) => rate);
|
|
7085
7699
|
this.current = null;
|
|
7086
7700
|
}
|
|
7701
|
+
getPlaybackCapabilities() {
|
|
7702
|
+
return { pause: true, resume: true };
|
|
7703
|
+
}
|
|
7087
7704
|
async capability() {
|
|
7088
7705
|
try {
|
|
7089
7706
|
const url = this.capabilityEndpoint || this.endpoint.replace(/\/speech$/, "/capabilities");
|
|
@@ -7158,18 +7775,26 @@ var HostAudioSpeakingEngine = class {
|
|
|
7158
7775
|
}
|
|
7159
7776
|
}
|
|
7160
7777
|
async playPrepared(prepared, options = {}) {
|
|
7161
|
-
const { signal, outputDeviceId = "", rate = 1, retainPrepared = false } = options;
|
|
7778
|
+
const { signal, outputDeviceId = "", rate = 1, volume = 1, retainPrepared = false } = options;
|
|
7162
7779
|
const playbackRate = this.playbackRate(rate);
|
|
7163
7780
|
if (!prepared?.audio) throw new TypeError("Prepared speech audio is required.");
|
|
7164
7781
|
await this.stop();
|
|
7165
7782
|
if (signal?.aborted) throw cancelled2();
|
|
7166
|
-
const operation = { prepared, audio: prepared.audio };
|
|
7783
|
+
const operation = { prepared, audio: prepared.audio, paused: false, ready: false };
|
|
7167
7784
|
this.current = operation;
|
|
7168
7785
|
const audio = operation.audio;
|
|
7169
7786
|
if (retainPrepared) audio.currentTime = 0;
|
|
7170
7787
|
audio.playbackRate = playbackRate;
|
|
7171
|
-
|
|
7172
|
-
|
|
7788
|
+
audio.volume = volume;
|
|
7789
|
+
try {
|
|
7790
|
+
if (outputDeviceId && typeof audio.setSinkId === "function")
|
|
7791
|
+
await audio.setSinkId(outputDeviceId);
|
|
7792
|
+
if (signal?.aborted || this.current !== operation) throw cancelled2();
|
|
7793
|
+
} catch (error) {
|
|
7794
|
+
if (this.current === operation) this.current = null;
|
|
7795
|
+
if (!retainPrepared) prepared.dispose();
|
|
7796
|
+
throw error;
|
|
7797
|
+
}
|
|
7173
7798
|
return new Promise((resolve, reject) => {
|
|
7174
7799
|
const cleanup = () => {
|
|
7175
7800
|
audio.removeEventListener("playing", started);
|
|
@@ -7200,7 +7825,8 @@ var HostAudioSpeakingEngine = class {
|
|
|
7200
7825
|
audio.addEventListener("ended", done, { once: true });
|
|
7201
7826
|
audio.addEventListener("error", failed, { once: true });
|
|
7202
7827
|
signal?.addEventListener("abort", aborted, { once: true });
|
|
7203
|
-
|
|
7828
|
+
operation.ready = true;
|
|
7829
|
+
if (!operation.paused) Promise.resolve(audio.play()).catch(failed);
|
|
7204
7830
|
});
|
|
7205
7831
|
}
|
|
7206
7832
|
async speak(text, options = {}) {
|
|
@@ -7212,6 +7838,9 @@ var HostAudioSpeakingEngine = class {
|
|
|
7212
7838
|
throw error;
|
|
7213
7839
|
}
|
|
7214
7840
|
}
|
|
7841
|
+
setVolume(volume) {
|
|
7842
|
+
if (this.current?.audio) this.current.audio.volume = volume;
|
|
7843
|
+
}
|
|
7215
7844
|
async stop() {
|
|
7216
7845
|
const operation = this.current;
|
|
7217
7846
|
if (!operation) return;
|
|
@@ -7229,13 +7858,15 @@ var HostAudioSpeakingEngine = class {
|
|
|
7229
7858
|
return { positionSeconds: audio.currentTime, durationSeconds: audio.duration };
|
|
7230
7859
|
}
|
|
7231
7860
|
pause() {
|
|
7232
|
-
if (!this.current?.audio || this.current.
|
|
7861
|
+
if (!this.current?.audio || this.current.paused) return false;
|
|
7862
|
+
this.current.paused = true;
|
|
7233
7863
|
this.current.audio.pause();
|
|
7234
7864
|
return true;
|
|
7235
7865
|
}
|
|
7236
7866
|
async resume() {
|
|
7237
|
-
if (!this.current?.audio || !this.current.audio.paused) return false;
|
|
7238
|
-
|
|
7867
|
+
if (!this.current?.audio || !this.current.paused && !this.current.audio.paused) return false;
|
|
7868
|
+
this.current.paused = false;
|
|
7869
|
+
if (this.current.ready) await this.current.audio.play();
|
|
7239
7870
|
return true;
|
|
7240
7871
|
}
|
|
7241
7872
|
};
|
|
@@ -7257,6 +7888,12 @@ var BrowserSpeakingEngine = class {
|
|
|
7257
7888
|
return [];
|
|
7258
7889
|
}
|
|
7259
7890
|
}
|
|
7891
|
+
getPlaybackCapabilities() {
|
|
7892
|
+
return {
|
|
7893
|
+
pause: typeof this.globals.speechSynthesis?.pause === "function",
|
|
7894
|
+
resume: typeof this.globals.speechSynthesis?.resume === "function"
|
|
7895
|
+
};
|
|
7896
|
+
}
|
|
7260
7897
|
capability() {
|
|
7261
7898
|
const supported = typeof this.globals.SpeechSynthesisUtterance === "function" && typeof this.globals.speechSynthesis?.speak === "function" && typeof this.globals.speechSynthesis?.cancel === "function" && this.voices().length > 0;
|
|
7262
7899
|
return {
|
|
@@ -7267,15 +7904,17 @@ var BrowserSpeakingEngine = class {
|
|
|
7267
7904
|
voiceURI: voice.voiceURI,
|
|
7268
7905
|
lang: voice.lang
|
|
7269
7906
|
})),
|
|
7270
|
-
|
|
7271
|
-
resume: typeof this.globals.speechSynthesis?.resume === "function",
|
|
7907
|
+
...this.getPlaybackCapabilities(),
|
|
7272
7908
|
...supported ? {} : {
|
|
7273
7909
|
reason: "Local browser speech synthesis is unavailable. Enable an installed local system voice, refresh the voice list, or choose another local speaking engine. Remote voices are not allowed."
|
|
7274
7910
|
}
|
|
7275
7911
|
};
|
|
7276
7912
|
}
|
|
7277
|
-
|
|
7278
|
-
|
|
7913
|
+
/** Inaudible preparation only: Web Speech does not expose pre-synthesized audio. */
|
|
7914
|
+
async prepare(text, options = {}) {
|
|
7915
|
+
return this._prepare(text, options);
|
|
7916
|
+
}
|
|
7917
|
+
_prepare(text, { voice, lang = this.lang, rate = 1, volume = 1, signal } = {}) {
|
|
7279
7918
|
if (signal?.aborted) throw abortError3();
|
|
7280
7919
|
if (typeof text !== "string") throw new TypeError("Speech text must be a string.");
|
|
7281
7920
|
if (!Number.isFinite(rate) || rate < 0.1 || rate > 10)
|
|
@@ -7283,18 +7922,61 @@ var BrowserSpeakingEngine = class {
|
|
|
7283
7922
|
const capability = this.capability();
|
|
7284
7923
|
if (!capability.supported) throw new Error(capability.reason);
|
|
7285
7924
|
const voices = this.voices();
|
|
7286
|
-
const chosen = voice == null ? voices.find((v) => v.lang?.toLowerCase() ===
|
|
7925
|
+
const chosen = voice == null ? voices.find((v) => v.lang?.toLowerCase() === lang.toLowerCase()) ?? voices[0] : voices.find(
|
|
7287
7926
|
(v) => typeof voice === "string" ? v.voiceURI === voice || v.name === voice : v === voice
|
|
7288
7927
|
);
|
|
7289
7928
|
if (!chosen)
|
|
7290
7929
|
throw new Error(
|
|
7291
7930
|
"The selected voice is not an available local browser voice. Choose a voice from voices()."
|
|
7292
7931
|
);
|
|
7293
|
-
|
|
7294
|
-
const
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7932
|
+
let disposed = false;
|
|
7933
|
+
const createUtterance = () => {
|
|
7934
|
+
if (disposed) throw abortError3();
|
|
7935
|
+
const available = this.voices().find((value) => value.voiceURI === chosen.voiceURI);
|
|
7936
|
+
if (!available) throw new Error("The prepared local browser voice is no longer available.");
|
|
7937
|
+
const utterance2 = new this.globals.SpeechSynthesisUtterance(text);
|
|
7938
|
+
utterance2.voice = available;
|
|
7939
|
+
utterance2.lang = available.lang || lang;
|
|
7940
|
+
utterance2.rate = rate;
|
|
7941
|
+
utterance2.volume = volume;
|
|
7942
|
+
return utterance2;
|
|
7943
|
+
};
|
|
7944
|
+
let utterance = createUtterance();
|
|
7945
|
+
return {
|
|
7946
|
+
text,
|
|
7947
|
+
rate,
|
|
7948
|
+
takeUtterance: () => {
|
|
7949
|
+
if (disposed) throw abortError3();
|
|
7950
|
+
if (!this.voices().some((value) => value.voiceURI === chosen.voiceURI))
|
|
7951
|
+
throw new Error("The prepared local browser voice is no longer available.");
|
|
7952
|
+
const next = utterance || createUtterance();
|
|
7953
|
+
utterance = null;
|
|
7954
|
+
return next;
|
|
7955
|
+
},
|
|
7956
|
+
dispose() {
|
|
7957
|
+
disposed = true;
|
|
7958
|
+
utterance = null;
|
|
7959
|
+
}
|
|
7960
|
+
};
|
|
7961
|
+
}
|
|
7962
|
+
async speak(text, options = {}) {
|
|
7963
|
+
this.stop();
|
|
7964
|
+
return this.playPrepared(this._prepare(text, options), options);
|
|
7965
|
+
}
|
|
7966
|
+
async playPrepared(prepared, { signal, volume, onPlaybackStart, retainPrepared = false } = {}) {
|
|
7967
|
+
this.stop();
|
|
7968
|
+
if (signal?.aborted) {
|
|
7969
|
+
if (!retainPrepared) prepared?.dispose?.();
|
|
7970
|
+
throw abortError3();
|
|
7971
|
+
}
|
|
7972
|
+
if (!prepared || typeof prepared.takeUtterance !== "function")
|
|
7973
|
+
throw new TypeError("Prepared browser speech is required.");
|
|
7974
|
+
if (!prepared.text.trim()) {
|
|
7975
|
+
if (!retainPrepared) prepared.dispose();
|
|
7976
|
+
return;
|
|
7977
|
+
}
|
|
7978
|
+
const utterance = prepared.takeUtterance();
|
|
7979
|
+
if (volume !== void 0) utterance.volume = volume;
|
|
7298
7980
|
return new Promise((resolve, reject) => {
|
|
7299
7981
|
const finish = (error) => {
|
|
7300
7982
|
if (this.current !== job) return;
|
|
@@ -7303,6 +7985,7 @@ var BrowserSpeakingEngine = class {
|
|
|
7303
7985
|
utterance.onend = null;
|
|
7304
7986
|
utterance.onerror = null;
|
|
7305
7987
|
signal?.removeEventListener("abort", cancel);
|
|
7988
|
+
if (!retainPrepared) prepared.dispose();
|
|
7306
7989
|
error ? reject(error) : resolve();
|
|
7307
7990
|
};
|
|
7308
7991
|
const cancel = () => {
|
|
@@ -7314,7 +7997,10 @@ var BrowserSpeakingEngine = class {
|
|
|
7314
7997
|
startedAt: null,
|
|
7315
7998
|
elapsedMs: 0,
|
|
7316
7999
|
hasStarted: false,
|
|
7317
|
-
estimatedDurationSeconds: Math.max(
|
|
8000
|
+
estimatedDurationSeconds: Math.max(
|
|
8001
|
+
1,
|
|
8002
|
+
Array.from(prepared.text).length / (14 * prepared.rate)
|
|
8003
|
+
)
|
|
7318
8004
|
};
|
|
7319
8005
|
this.current = job;
|
|
7320
8006
|
utterance.onstart = () => {
|
|
@@ -7337,7 +8023,7 @@ var BrowserSpeakingEngine = class {
|
|
|
7337
8023
|
return;
|
|
7338
8024
|
}
|
|
7339
8025
|
try {
|
|
7340
|
-
this.globals.speechSynthesis.resume?.();
|
|
8026
|
+
if (this.globals.speechSynthesis.paused) this.globals.speechSynthesis.resume?.();
|
|
7341
8027
|
this.globals.speechSynthesis.speak(utterance);
|
|
7342
8028
|
} catch (error) {
|
|
7343
8029
|
finish(error);
|
|
@@ -7392,16 +8078,16 @@ var QwenHttpSpeakingEngine = class extends HostAudioSpeakingEngine {
|
|
|
7392
8078
|
};
|
|
7393
8079
|
|
|
7394
8080
|
// src/modules/settings/components/createLiveVoiceSettings.tsx
|
|
7395
|
-
var
|
|
8081
|
+
var import_react59 = __toESM(require("react"), 1);
|
|
7396
8082
|
|
|
7397
8083
|
// src/modules/settings/components/LiveVoiceSettings.tsx
|
|
7398
|
-
var
|
|
8084
|
+
var import_react58 = __toESM(require("react"), 1);
|
|
7399
8085
|
|
|
7400
8086
|
// src/modules/settings/hooks/useAudioDevices.ts
|
|
7401
|
-
var
|
|
8087
|
+
var import_react33 = __toESM(require("react"), 1);
|
|
7402
8088
|
function useAudioDevices() {
|
|
7403
|
-
const [audioDevices, setAudioDevices] =
|
|
7404
|
-
|
|
8089
|
+
const [audioDevices, setAudioDevices] = import_react33.default.useState([]);
|
|
8090
|
+
import_react33.default.useEffect(() => {
|
|
7405
8091
|
let active = true;
|
|
7406
8092
|
const refresh = async () => {
|
|
7407
8093
|
try {
|
|
@@ -7431,10 +8117,10 @@ function createDeviceOptions(devices, kind, systemDefault, fallback) {
|
|
|
7431
8117
|
}
|
|
7432
8118
|
|
|
7433
8119
|
// src/modules/settings/hooks/useReleaseStatus.ts
|
|
7434
|
-
var
|
|
8120
|
+
var import_react34 = __toESM(require("react"), 1);
|
|
7435
8121
|
|
|
7436
8122
|
// src/modules/settings/services/releases.ts
|
|
7437
|
-
var CURRENT_VERSION = "0.5.
|
|
8123
|
+
var CURRENT_VERSION = "0.5.2";
|
|
7438
8124
|
var TESTED_DSH_VERSION = "0.2.1-alpha.2";
|
|
7439
8125
|
var REPOSITORY_URL = "https://github.com/victorwads/dsh-live-voice";
|
|
7440
8126
|
var RELEASES_URL = `${REPOSITORY_URL}/releases`;
|
|
@@ -7536,10 +8222,10 @@ function hasNewerRelease(release, currentVersion = CURRENT_VERSION) {
|
|
|
7536
8222
|
|
|
7537
8223
|
// src/modules/settings/hooks/useReleaseStatus.ts
|
|
7538
8224
|
function useReleaseStatus() {
|
|
7539
|
-
const [latestRelease, setLatestRelease] =
|
|
8225
|
+
const [latestRelease, setLatestRelease] = import_react34.default.useState(
|
|
7540
8226
|
null
|
|
7541
8227
|
);
|
|
7542
|
-
|
|
8228
|
+
import_react34.default.useEffect(() => {
|
|
7543
8229
|
let active = true;
|
|
7544
8230
|
void checkLatestRelease().then((result) => {
|
|
7545
8231
|
if (active) setLatestRelease(result.release);
|
|
@@ -7552,10 +8238,10 @@ function useReleaseStatus() {
|
|
|
7552
8238
|
}
|
|
7553
8239
|
|
|
7554
8240
|
// src/modules/settings/sections/conversation/ConversationSettingsSection.tsx
|
|
7555
|
-
var
|
|
8241
|
+
var import_react40 = __toESM(require("react"), 1);
|
|
7556
8242
|
|
|
7557
8243
|
// src/modules/settings/sections/conversation/DeliverySettings.tsx
|
|
7558
|
-
var
|
|
8244
|
+
var import_react35 = __toESM(require("react"), 1);
|
|
7559
8245
|
function DeliverySettings({
|
|
7560
8246
|
settings,
|
|
7561
8247
|
updateSettings
|
|
@@ -7563,8 +8249,8 @@ function DeliverySettings({
|
|
|
7563
8249
|
const { scoped } = useLanguage((ctx) => ctx.settings);
|
|
7564
8250
|
const mode = settings.sendingMode || "manual";
|
|
7565
8251
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
7566
|
-
const busyEnterHelpId =
|
|
7567
|
-
return /* @__PURE__ */
|
|
8252
|
+
const busyEnterHelpId = import_react35.default.useId();
|
|
8253
|
+
return /* @__PURE__ */ import_react35.default.createElement(import_react35.default.Fragment, null, /* @__PURE__ */ import_react35.default.createElement(
|
|
7568
8254
|
SelectField,
|
|
7569
8255
|
{
|
|
7570
8256
|
label: scoped.delivery.label(),
|
|
@@ -7576,11 +8262,12 @@ function DeliverySettings({
|
|
|
7576
8262
|
],
|
|
7577
8263
|
onChange: (event) => updateSettings({ sendingMode: event.target.value })
|
|
7578
8264
|
}
|
|
7579
|
-
), /* @__PURE__ */
|
|
8265
|
+
), /* @__PURE__ */ import_react35.default.createElement(
|
|
7580
8266
|
SelectField,
|
|
7581
8267
|
{
|
|
7582
8268
|
label: scoped.delivery.dshEnterQuestion(),
|
|
7583
8269
|
"aria-describedby": busyEnterHelpId,
|
|
8270
|
+
hint: scoped.delivery.dshEnterHelp(),
|
|
7584
8271
|
value: settings.dshBusyEnterBehavior || "queue",
|
|
7585
8272
|
options: [
|
|
7586
8273
|
{ value: "steer", label: scoped.delivery.dshEnterSteer() },
|
|
@@ -7588,7 +8275,7 @@ function DeliverySettings({
|
|
|
7588
8275
|
],
|
|
7589
8276
|
onChange: (event) => updateSettings({ dshBusyEnterBehavior: event.target.value })
|
|
7590
8277
|
}
|
|
7591
|
-
),
|
|
8278
|
+
), mode !== "manual" ? /* @__PURE__ */ import_react35.default.createElement(
|
|
7592
8279
|
SelectField,
|
|
7593
8280
|
{
|
|
7594
8281
|
label: scoped.autoSend.delay(),
|
|
@@ -7599,21 +8286,21 @@ function DeliverySettings({
|
|
|
7599
8286
|
})),
|
|
7600
8287
|
onChange: (event) => updateSettings({ autoSendDelaySeconds: Number(event.target.value) })
|
|
7601
8288
|
}
|
|
7602
|
-
) :
|
|
8289
|
+
) : null);
|
|
7603
8290
|
}
|
|
7604
8291
|
|
|
7605
8292
|
// src/modules/settings/sections/conversation/HoldToTalkSettings.tsx
|
|
7606
|
-
var
|
|
8293
|
+
var import_react36 = __toESM(require("react"), 1);
|
|
7607
8294
|
function HoldToTalkSettings({
|
|
7608
8295
|
settings,
|
|
7609
8296
|
updateSettings
|
|
7610
8297
|
}) {
|
|
7611
8298
|
const { scoped: recognition } = useLanguage((ctx) => ctx.recognition);
|
|
7612
|
-
return /* @__PURE__ */
|
|
8299
|
+
return /* @__PURE__ */ import_react36.default.createElement(
|
|
7613
8300
|
CheckboxField,
|
|
7614
8301
|
{
|
|
7615
8302
|
label: recognition.holdToTalk.enabled(),
|
|
7616
|
-
|
|
8303
|
+
hint: recognition.holdToTalk.help(),
|
|
7617
8304
|
checked: settings.holdToTalkEnabled !== false,
|
|
7618
8305
|
onChange: (event) => updateSettings({ holdToTalkEnabled: event.target.checked })
|
|
7619
8306
|
}
|
|
@@ -7621,17 +8308,18 @@ function HoldToTalkSettings({
|
|
|
7621
8308
|
}
|
|
7622
8309
|
|
|
7623
8310
|
// src/modules/settings/sections/conversation/VoiceModeSettings.tsx
|
|
7624
|
-
var
|
|
8311
|
+
var import_react37 = __toESM(require("react"), 1);
|
|
7625
8312
|
function VoiceModeSettings({
|
|
7626
8313
|
settings,
|
|
7627
8314
|
updateSettings
|
|
7628
8315
|
}) {
|
|
7629
8316
|
const { scoped: recognition } = useLanguage((ctx) => ctx.recognition);
|
|
7630
8317
|
const mode = settings.mode || "speaker";
|
|
7631
|
-
return /* @__PURE__ */
|
|
8318
|
+
return /* @__PURE__ */ import_react37.default.createElement(import_react37.default.Fragment, null, /* @__PURE__ */ import_react37.default.createElement(
|
|
7632
8319
|
SelectField,
|
|
7633
8320
|
{
|
|
7634
8321
|
label: recognition.mode.label(),
|
|
8322
|
+
hint: mode === "headphones" ? recognition.headphoneMode.help() : recognition.speakerMode.help(),
|
|
7635
8323
|
value: mode,
|
|
7636
8324
|
options: [
|
|
7637
8325
|
{ value: "speaker", label: recognition.speakerMode.label() },
|
|
@@ -7639,19 +8327,20 @@ function VoiceModeSettings({
|
|
|
7639
8327
|
],
|
|
7640
8328
|
onChange: (event) => updateSettings({ mode: event.target.value })
|
|
7641
8329
|
}
|
|
7642
|
-
)
|
|
8330
|
+
));
|
|
7643
8331
|
}
|
|
7644
8332
|
|
|
7645
8333
|
// src/modules/settings/sections/conversation/ConversationDelaySettings.tsx
|
|
7646
|
-
var
|
|
8334
|
+
var import_react38 = __toESM(require("react"), 1);
|
|
7647
8335
|
var DELAYS = [0, 1, 2, 3, 4];
|
|
7648
8336
|
function ConversationDelaySettings({ settings, updateSettings }) {
|
|
7649
8337
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
7650
8338
|
const { scoped: speak } = useLanguage((ctx) => ctx.speak);
|
|
7651
|
-
return /* @__PURE__ */
|
|
8339
|
+
return /* @__PURE__ */ import_react38.default.createElement(import_react38.default.Fragment, null, /* @__PURE__ */ import_react38.default.createElement(
|
|
7652
8340
|
SelectField,
|
|
7653
8341
|
{
|
|
7654
8342
|
label: speak.responseDelay.label(),
|
|
8343
|
+
hint: speak.responseDelay.help(),
|
|
7655
8344
|
value: String(settings.assistantSpeechDelaySeconds ?? 0),
|
|
7656
8345
|
options: DELAYS.map((seconds) => ({
|
|
7657
8346
|
value: String(seconds),
|
|
@@ -7659,41 +8348,43 @@ function ConversationDelaySettings({ settings, updateSettings }) {
|
|
|
7659
8348
|
})),
|
|
7660
8349
|
onChange: (event) => updateSettings({ assistantSpeechDelaySeconds: Number(event.target.value) })
|
|
7661
8350
|
}
|
|
7662
|
-
)
|
|
8351
|
+
));
|
|
7663
8352
|
}
|
|
7664
8353
|
|
|
7665
8354
|
// src/modules/settings/sections/speak/PlaybackPolicySettings.tsx
|
|
7666
|
-
var
|
|
8355
|
+
var import_react39 = __toESM(require("react"), 1);
|
|
7667
8356
|
function PlaybackPolicySettings({ settings, updateSettings }) {
|
|
7668
8357
|
const { scoped: speak } = useLanguage((ctx) => ctx.speak);
|
|
7669
|
-
return /* @__PURE__ */
|
|
8358
|
+
return /* @__PURE__ */ import_react39.default.createElement(import_react39.default.Fragment, null, /* @__PURE__ */ import_react39.default.createElement(
|
|
7670
8359
|
CheckboxField,
|
|
7671
8360
|
{
|
|
7672
8361
|
label: speak.autoPlayback.label(),
|
|
8362
|
+
hint: speak.autoPlayback.help(),
|
|
7673
8363
|
checked: settings.announceAssistantMessages !== false,
|
|
7674
8364
|
onChange: (event) => updateSettings({ announceAssistantMessages: event.target.checked })
|
|
7675
8365
|
}
|
|
7676
|
-
), /* @__PURE__ */
|
|
8366
|
+
), /* @__PURE__ */ import_react39.default.createElement(
|
|
7677
8367
|
CheckboxField,
|
|
7678
8368
|
{
|
|
7679
8369
|
label: speak.interruption.enabled(),
|
|
8370
|
+
hint: settings.interruptSpeechOnUserMessage ? speak.interruption.enabledHelp() : speak.interruption.disabledHelp(),
|
|
7680
8371
|
checked: Boolean(settings.interruptSpeechOnUserMessage),
|
|
7681
8372
|
onChange: (event) => updateSettings({ interruptSpeechOnUserMessage: event.target.checked })
|
|
7682
8373
|
}
|
|
7683
|
-
)
|
|
8374
|
+
));
|
|
7684
8375
|
}
|
|
7685
8376
|
|
|
7686
8377
|
// src/modules/settings/sections/conversation/ConversationSettingsSection.tsx
|
|
7687
8378
|
function ConversationSettingsSection(props) {
|
|
7688
8379
|
const { scoped: settingsLanguage } = useLanguage((ctx) => ctx.settings);
|
|
7689
|
-
return /* @__PURE__ */
|
|
8380
|
+
return /* @__PURE__ */ import_react40.default.createElement(SettingsCard, null, /* @__PURE__ */ import_react40.default.createElement("div", { className: "dlv-settings-card-body" }, /* @__PURE__ */ import_react40.default.createElement(SettingsSection, { title: settingsLanguage.layout.delivery(), icon: "send" }, /* @__PURE__ */ import_react40.default.createElement(DeliverySettings, { ...props })), /* @__PURE__ */ import_react40.default.createElement(SettingsSection, { title: settingsLanguage.layout.listening(), icon: "headphones" }, /* @__PURE__ */ import_react40.default.createElement(VoiceModeSettings, { ...props }), /* @__PURE__ */ import_react40.default.createElement(PlaybackPolicySettings, { ...props }), /* @__PURE__ */ import_react40.default.createElement(ConversationDelaySettings, { ...props })), /* @__PURE__ */ import_react40.default.createElement(SettingsSection, { title: settingsLanguage.layout.shortcut(), icon: "keyboard" }, /* @__PURE__ */ import_react40.default.createElement(HoldToTalkSettings, { ...props }))));
|
|
7690
8381
|
}
|
|
7691
8382
|
|
|
7692
8383
|
// src/modules/settings/sections/recognition/RecognitionEngineSettings.tsx
|
|
7693
|
-
var
|
|
8384
|
+
var import_react43 = __toESM(require("react"), 1);
|
|
7694
8385
|
|
|
7695
8386
|
// src/modules/core/qwen/QwenSettings.tsx
|
|
7696
|
-
var
|
|
8387
|
+
var import_react41 = __toESM(require("react"), 1);
|
|
7697
8388
|
var BASE = "/api/dsh-live-voice/qwen";
|
|
7698
8389
|
var UNLOADED = "dsh-live-voice.speak.qwen.restartRequired";
|
|
7699
8390
|
async function qwenSettingsRequest(path, { method = "GET", config, signal } = {}, fetchImpl = globalThis.fetch) {
|
|
@@ -7722,15 +8413,15 @@ function QwenSettings({ controller }) {
|
|
|
7722
8413
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
7723
8414
|
const { scoped: recognition } = useLanguage((ctx) => ctx.recognition);
|
|
7724
8415
|
const { scoped: speak } = useLanguage((ctx) => ctx.speak);
|
|
7725
|
-
const [draft, setDraft] =
|
|
8416
|
+
const [draft, setDraft] = import_react41.default.useState({
|
|
7726
8417
|
baseUrl: "http://127.0.0.1:8080/",
|
|
7727
8418
|
timeoutMs: 3e5
|
|
7728
8419
|
});
|
|
7729
|
-
const [busy, setBusy] =
|
|
7730
|
-
const [loaded, setLoaded] =
|
|
7731
|
-
const [error, setError] =
|
|
7732
|
-
const [message2, setMessage] =
|
|
7733
|
-
const active =
|
|
8420
|
+
const [busy, setBusy] = import_react41.default.useState(true);
|
|
8421
|
+
const [loaded, setLoaded] = import_react41.default.useState(false);
|
|
8422
|
+
const [error, setError] = import_react41.default.useState("");
|
|
8423
|
+
const [message2, setMessage] = import_react41.default.useState("");
|
|
8424
|
+
const active = import_react41.default.useRef(null);
|
|
7734
8425
|
const translateStatus = (value) => ({
|
|
7735
8426
|
"dsh-live-voice.commons.connection.unsaved": commons.connection.unsaved(),
|
|
7736
8427
|
"dsh-live-voice.speak.qwen.saved": speak.qwen.saved(),
|
|
@@ -7764,7 +8455,6 @@ function QwenSettings({ controller }) {
|
|
|
7764
8455
|
if (!abort.signal.aborted) {
|
|
7765
8456
|
setDraft(value);
|
|
7766
8457
|
setMessage("dsh-live-voice.speak.qwen.saved");
|
|
7767
|
-
await controller.refreshCapabilities?.();
|
|
7768
8458
|
}
|
|
7769
8459
|
} else {
|
|
7770
8460
|
const value = await qwenSettingsRequest("/test", {
|
|
@@ -7784,13 +8474,13 @@ function QwenSettings({ controller }) {
|
|
|
7784
8474
|
if (!abort.signal.aborted) setBusy(false);
|
|
7785
8475
|
}
|
|
7786
8476
|
}
|
|
7787
|
-
|
|
8477
|
+
import_react41.default.useEffect(() => {
|
|
7788
8478
|
void run("load");
|
|
7789
8479
|
return () => active.current?.abort();
|
|
7790
8480
|
}, []);
|
|
7791
8481
|
const field = (label, key, type = "text") => {
|
|
7792
8482
|
const Field = type === "number" ? NumberField : TextField;
|
|
7793
|
-
return /* @__PURE__ */
|
|
8483
|
+
return /* @__PURE__ */ import_react41.default.createElement(
|
|
7794
8484
|
Field,
|
|
7795
8485
|
{
|
|
7796
8486
|
label,
|
|
@@ -7806,11 +8496,17 @@ function QwenSettings({ controller }) {
|
|
|
7806
8496
|
}
|
|
7807
8497
|
);
|
|
7808
8498
|
};
|
|
7809
|
-
return /* @__PURE__ */
|
|
8499
|
+
return /* @__PURE__ */ import_react41.default.createElement(import_react41.default.Fragment, null, /* @__PURE__ */ import_react41.default.createElement("p", null, recognition.qwen.hostHelp()), field(speak.qwen.endpoint(), "baseUrl"), field(commons.connection.timeout(), "timeoutMs", "number"), /* @__PURE__ */ import_react41.default.createElement("div", { className: "dlv-settings-actions" }, /* @__PURE__ */ import_react41.default.createElement("button", { type: "button", disabled: busy || !loaded, onClick: () => run("save") }, speak.qwen.save()), /* @__PURE__ */ import_react41.default.createElement("button", { type: "button", disabled: busy || !loaded, onClick: () => run("test") }, speak.qwen.test()), /* @__PURE__ */ import_react41.default.createElement("button", { type: "button", disabled: busy, onClick: () => run("load") }, commons.connection.reload())), busy && /* @__PURE__ */ import_react41.default.createElement("p", { role: "status" }, commons.connection.contactingHost()), message2 && /* @__PURE__ */ import_react41.default.createElement("p", { role: "status" }, translateStatus(message2)), error && /* @__PURE__ */ import_react41.default.createElement("p", { role: "alert" }, translateStatus(error)));
|
|
8500
|
+
}
|
|
8501
|
+
|
|
8502
|
+
// src/modules/core/engineSelection.ts
|
|
8503
|
+
var recognitionEngineOrder = Object.freeze(["browser", "qwen-http", "whisper-http"]);
|
|
8504
|
+
function speakingEngineOrder(hostPlatform) {
|
|
8505
|
+
return hostPlatform === "darwin" ? ["say", "browser", "qwen-http"] : ["browser", "qwen-http", "say"];
|
|
7810
8506
|
}
|
|
7811
8507
|
|
|
7812
8508
|
// src/modules/recognition/engines/whisper/WhisperSettings.tsx
|
|
7813
|
-
var
|
|
8509
|
+
var import_react42 = __toESM(require("react"), 1);
|
|
7814
8510
|
var BASE2 = "/api/dsh-live-voice/whisper";
|
|
7815
8511
|
var UNLOADED2 = "dsh-live-voice.recognition.whisper.restartRequired";
|
|
7816
8512
|
async function whisperSettingsRequest(path, { method = "GET", config, signal } = {}, fetchImpl = globalThis.fetch) {
|
|
@@ -7839,16 +8535,16 @@ function WhisperSettings({ controller }) {
|
|
|
7839
8535
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
7840
8536
|
const { scoped: recognition } = useLanguage((ctx) => ctx.recognition);
|
|
7841
8537
|
const { scoped: settings } = useLanguage((ctx) => ctx.settings);
|
|
7842
|
-
const [draft, setDraft] =
|
|
8538
|
+
const [draft, setDraft] = import_react42.default.useState({
|
|
7843
8539
|
url: "http://127.0.0.1:8080/inference",
|
|
7844
8540
|
healthUrl: "/health",
|
|
7845
8541
|
timeoutMs: 3e4
|
|
7846
8542
|
});
|
|
7847
|
-
const [busy, setBusy] =
|
|
7848
|
-
const [loaded, setLoaded] =
|
|
7849
|
-
const [error, setError] =
|
|
7850
|
-
const [message2, setMessage] =
|
|
7851
|
-
const active =
|
|
8543
|
+
const [busy, setBusy] = import_react42.default.useState(true);
|
|
8544
|
+
const [loaded, setLoaded] = import_react42.default.useState(false);
|
|
8545
|
+
const [error, setError] = import_react42.default.useState("");
|
|
8546
|
+
const [message2, setMessage] = import_react42.default.useState("");
|
|
8547
|
+
const active = import_react42.default.useRef(null);
|
|
7852
8548
|
const translateStatus = (value) => ({
|
|
7853
8549
|
"dsh-live-voice.commons.connection.unsaved": commons.connection.unsaved(),
|
|
7854
8550
|
"dsh-live-voice.recognition.whisper.saved": recognition.whisper.saved(),
|
|
@@ -7882,7 +8578,6 @@ function WhisperSettings({ controller }) {
|
|
|
7882
8578
|
if (!abort.signal.aborted) {
|
|
7883
8579
|
setDraft(value);
|
|
7884
8580
|
setMessage("dsh-live-voice.recognition.whisper.saved");
|
|
7885
|
-
await controller.refreshCapabilities?.();
|
|
7886
8581
|
}
|
|
7887
8582
|
} else {
|
|
7888
8583
|
const value = await whisperSettingsRequest("/test", {
|
|
@@ -7902,13 +8597,13 @@ function WhisperSettings({ controller }) {
|
|
|
7902
8597
|
if (!abort.signal.aborted) setBusy(false);
|
|
7903
8598
|
}
|
|
7904
8599
|
}
|
|
7905
|
-
|
|
8600
|
+
import_react42.default.useEffect(() => {
|
|
7906
8601
|
void run("load");
|
|
7907
8602
|
return () => active.current?.abort();
|
|
7908
8603
|
}, []);
|
|
7909
8604
|
const field = (label, key, type = "text") => {
|
|
7910
8605
|
const Field = type === "number" ? NumberField : TextField;
|
|
7911
|
-
return /* @__PURE__ */
|
|
8606
|
+
return /* @__PURE__ */ import_react42.default.createElement(
|
|
7912
8607
|
Field,
|
|
7913
8608
|
{
|
|
7914
8609
|
label,
|
|
@@ -7924,7 +8619,7 @@ function WhisperSettings({ controller }) {
|
|
|
7924
8619
|
}
|
|
7925
8620
|
);
|
|
7926
8621
|
};
|
|
7927
|
-
return /* @__PURE__ */
|
|
8622
|
+
return /* @__PURE__ */ import_react42.default.createElement(import_react42.default.Fragment, null, /* @__PURE__ */ import_react42.default.createElement("p", null, settings.whisper.hostHelp()), field(commons.connection.endpoint(), "url"), field(commons.connection.healthEndpoint(), "healthUrl"), field(commons.connection.timeout(), "timeoutMs", "number"), /* @__PURE__ */ import_react42.default.createElement("div", { className: "dlv-settings-actions" }, /* @__PURE__ */ import_react42.default.createElement("button", { type: "button", disabled: busy || !loaded, onClick: () => run("save") }, recognition.whisper.save()), /* @__PURE__ */ import_react42.default.createElement("button", { type: "button", disabled: busy || !loaded, onClick: () => run("test") }, commons.connection.test()), /* @__PURE__ */ import_react42.default.createElement("button", { type: "button", disabled: busy, onClick: () => run("load") }, commons.connection.reload())), busy && /* @__PURE__ */ import_react42.default.createElement("p", { role: "status" }, commons.connection.contactingHost()), message2 && /* @__PURE__ */ import_react42.default.createElement("p", { role: "status" }, translateStatus(message2)), error && /* @__PURE__ */ import_react42.default.createElement("p", { role: "alert" }, translateStatus(error)));
|
|
7928
8623
|
}
|
|
7929
8624
|
|
|
7930
8625
|
// src/modules/settings/sections/recognition/RecognitionEngineSettings.tsx
|
|
@@ -7941,32 +8636,22 @@ function RecognitionEngineSettings({
|
|
|
7941
8636
|
const setEngine = (next) => updateSettings(
|
|
7942
8637
|
next === "browser" && settings.recognitionLang === "auto" ? { recognitionEngine: next, recognitionLang: "pt-BR" } : { recognitionEngine: next }
|
|
7943
8638
|
);
|
|
7944
|
-
return /* @__PURE__ */
|
|
8639
|
+
return /* @__PURE__ */ import_react43.default.createElement(import_react43.default.Fragment, null, /* @__PURE__ */ import_react43.default.createElement(
|
|
7945
8640
|
SelectField,
|
|
7946
8641
|
{
|
|
7947
8642
|
label: recognition.engine.label(),
|
|
7948
8643
|
value: engine,
|
|
7949
|
-
options:
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
}
|
|
7956
|
-
|
|
7957
|
-
value: "qwen-http",
|
|
7958
|
-
label: recognition.qwen.label(),
|
|
7959
|
-
disabled: capabilities["qwen-http-recognition"]?.supported === false
|
|
7960
|
-
},
|
|
7961
|
-
{
|
|
7962
|
-
value: "whisper-http",
|
|
7963
|
-
label: recognition.whisper.label(),
|
|
7964
|
-
disabled: capabilities["whisper-http"]?.supported === false
|
|
7965
|
-
}
|
|
7966
|
-
],
|
|
8644
|
+
options: recognitionEngineOrder.map((value) => ({
|
|
8645
|
+
value,
|
|
8646
|
+
label: {
|
|
8647
|
+
browser: recognition.browser.label(),
|
|
8648
|
+
"qwen-http": recognition.qwen.label(),
|
|
8649
|
+
"whisper-http": recognition.whisper.label()
|
|
8650
|
+
}[value]
|
|
8651
|
+
})),
|
|
7967
8652
|
onChange: (event) => setEngine(event.target.value)
|
|
7968
8653
|
}
|
|
7969
|
-
), /* @__PURE__ */
|
|
8654
|
+
), /* @__PURE__ */ import_react43.default.createElement(
|
|
7970
8655
|
SelectField,
|
|
7971
8656
|
{
|
|
7972
8657
|
label: recognition.microphone.device(),
|
|
@@ -7979,7 +8664,7 @@ function RecognitionEngineSettings({
|
|
|
7979
8664
|
),
|
|
7980
8665
|
onChange: (event) => updateSettings({ inputDeviceId: event.target.value })
|
|
7981
8666
|
}
|
|
7982
|
-
), /* @__PURE__ */
|
|
8667
|
+
), /* @__PURE__ */ import_react43.default.createElement(
|
|
7983
8668
|
SelectField,
|
|
7984
8669
|
{
|
|
7985
8670
|
label: recognition.language.label(),
|
|
@@ -7987,41 +8672,44 @@ function RecognitionEngineSettings({
|
|
|
7987
8672
|
options: [
|
|
7988
8673
|
...engine === "browser" ? [] : [{ value: "auto", label: recognition.language.automatic() }],
|
|
7989
8674
|
{ value: "pt-BR", label: "Portugu\xEAs (Brasil)" },
|
|
7990
|
-
{ value: "en-US", label: "English (US)" }
|
|
8675
|
+
{ value: "en-US", label: "English (US)" },
|
|
8676
|
+
{ value: "zh-CN", label: recognition.language.options.chinese() },
|
|
8677
|
+
{ value: "es-ES", label: recognition.language.options.spanish() },
|
|
8678
|
+
{ value: "fr-FR", label: recognition.language.options.french() }
|
|
7991
8679
|
],
|
|
7992
8680
|
onChange: (event) => updateSettings({ recognitionLang: event.target.value })
|
|
7993
8681
|
}
|
|
7994
|
-
), engine === "browser" && /* @__PURE__ */
|
|
8682
|
+
), engine === "browser" && /* @__PURE__ */ import_react43.default.createElement(import_react43.default.Fragment, null, /* @__PURE__ */ import_react43.default.createElement("p", null, recognition.browser.help()), /* @__PURE__ */ import_react43.default.createElement(
|
|
7995
8683
|
CheckboxField,
|
|
7996
8684
|
{
|
|
7997
8685
|
label: recognition.browser.localProcessing(),
|
|
7998
8686
|
checked: settings.recognitionProcessLocally !== false,
|
|
7999
8687
|
onChange: (event) => updateSettings({ recognitionProcessLocally: event.target.checked })
|
|
8000
8688
|
}
|
|
8001
|
-
), settings.recognitionProcessLocally !== false ? /* @__PURE__ */
|
|
8689
|
+
), settings.recognitionProcessLocally !== false ? /* @__PURE__ */ import_react43.default.createElement(
|
|
8002
8690
|
CheckboxField,
|
|
8003
8691
|
{
|
|
8004
8692
|
label: recognition.browser.autoInstallPack(),
|
|
8005
8693
|
checked: settings.recognitionAutoInstall !== false,
|
|
8006
8694
|
onChange: (event) => updateSettings({ recognitionAutoInstall: event.target.checked })
|
|
8007
8695
|
}
|
|
8008
|
-
) : /* @__PURE__ */
|
|
8696
|
+
) : /* @__PURE__ */ import_react43.default.createElement("p", { role: "status" }, recognition.browser.remoteServiceWarning())), engine === "whisper-http" && /* @__PURE__ */ import_react43.default.createElement(SettingsSubcard, { title: commons.connection.title(), icon: "link" }, /* @__PURE__ */ import_react43.default.createElement("p", null, recognition.whisper.captureHelp()), /* @__PURE__ */ import_react43.default.createElement(WhisperSettings, { controller })), engine === "qwen-http" && /* @__PURE__ */ import_react43.default.createElement(SettingsSubcard, { title: commons.connection.title(), icon: "link" }, /* @__PURE__ */ import_react43.default.createElement("p", null, recognition.qwen.captureHelp()), settings.engine !== "qwen-http" && /* @__PURE__ */ import_react43.default.createElement(QwenSettings, { controller })));
|
|
8009
8697
|
}
|
|
8010
8698
|
|
|
8011
8699
|
// src/modules/settings/sections/recognition/RecognitionFilterSettings.tsx
|
|
8012
|
-
var
|
|
8700
|
+
var import_react44 = __toESM(require("react"), 1);
|
|
8013
8701
|
function RecognitionFilterSettings({ settings, updateSettings }) {
|
|
8014
8702
|
const { scoped: recognition } = useLanguage((ctx) => ctx.recognition);
|
|
8015
8703
|
const enabled = settings.recognitionFilterEnabled !== false;
|
|
8016
|
-
return /* @__PURE__ */
|
|
8704
|
+
return /* @__PURE__ */ import_react44.default.createElement(SettingsSection, { title: recognition.minimumWords.label(), icon: "filter" }, /* @__PURE__ */ import_react44.default.createElement(
|
|
8017
8705
|
CheckboxField,
|
|
8018
8706
|
{
|
|
8019
8707
|
label: recognition.minimumWords.enabled(),
|
|
8020
|
-
|
|
8708
|
+
hint: recognition.minimumWords.help(),
|
|
8021
8709
|
checked: enabled,
|
|
8022
8710
|
onChange: (event) => updateSettings({ recognitionFilterEnabled: event.target.checked })
|
|
8023
8711
|
}
|
|
8024
|
-
), /* @__PURE__ */
|
|
8712
|
+
), /* @__PURE__ */ import_react44.default.createElement(
|
|
8025
8713
|
NumberField,
|
|
8026
8714
|
{
|
|
8027
8715
|
label: recognition.minimumWords.label(),
|
|
@@ -8039,14 +8727,14 @@ function RecognitionFilterSettings({ settings, updateSettings }) {
|
|
|
8039
8727
|
}
|
|
8040
8728
|
|
|
8041
8729
|
// src/modules/settings/sections/recognition/RecognitionSettingsSection.tsx
|
|
8042
|
-
var
|
|
8730
|
+
var import_react50 = __toESM(require("react"), 1);
|
|
8043
8731
|
|
|
8044
8732
|
// src/modules/settings/sections/recognition/SilenceDetectionSettings.tsx
|
|
8045
|
-
var
|
|
8733
|
+
var import_react45 = __toESM(require("react"), 1);
|
|
8046
8734
|
function SilenceDetectionSettings({ settings, updateSettings }) {
|
|
8047
8735
|
const { scoped: recognition } = useLanguage((ctx) => ctx.recognition);
|
|
8048
|
-
const [sileroAvailable, setSileroAvailable] =
|
|
8049
|
-
|
|
8736
|
+
const [sileroAvailable, setSileroAvailable] = import_react45.default.useState(false);
|
|
8737
|
+
import_react45.default.useEffect(() => {
|
|
8050
8738
|
let current = true;
|
|
8051
8739
|
void sileroVadAvailable().then((available) => {
|
|
8052
8740
|
if (current) setSileroAvailable(available);
|
|
@@ -8058,15 +8746,16 @@ function SilenceDetectionSettings({ settings, updateSettings }) {
|
|
|
8058
8746
|
const savedCustomMs = normalizeCustomSilenceMs(settings.voiceDetectionCustomSilenceMs);
|
|
8059
8747
|
if (!usesPluginVoiceDetection(settings.recognitionEngine)) return null;
|
|
8060
8748
|
const selected = settings.voiceDetectionPreset || defaultSettings.voiceDetectionPreset;
|
|
8061
|
-
return /* @__PURE__ */
|
|
8062
|
-
|
|
8749
|
+
return /* @__PURE__ */ import_react45.default.createElement(
|
|
8750
|
+
SettingsSection,
|
|
8063
8751
|
{
|
|
8064
8752
|
title: recognition.silenceDetection.label(),
|
|
8065
8753
|
ariaLabel: recognition.silenceDetection.title(),
|
|
8066
|
-
icon: "pause"
|
|
8754
|
+
icon: "pause",
|
|
8755
|
+
defaultOpen: false
|
|
8067
8756
|
},
|
|
8068
|
-
/* @__PURE__ */
|
|
8069
|
-
/* @__PURE__ */
|
|
8757
|
+
/* @__PURE__ */ import_react45.default.createElement("p", null, recognition.silenceDetection.help()),
|
|
8758
|
+
/* @__PURE__ */ import_react45.default.createElement(
|
|
8070
8759
|
SelectField,
|
|
8071
8760
|
{
|
|
8072
8761
|
label: recognition.silenceDetection.detector.label(),
|
|
@@ -8082,7 +8771,7 @@ function SilenceDetectionSettings({ settings, updateSettings }) {
|
|
|
8082
8771
|
onChange: (event) => updateSettings({ voiceDetectionEngine: event.target.value })
|
|
8083
8772
|
}
|
|
8084
8773
|
),
|
|
8085
|
-
/* @__PURE__ */
|
|
8774
|
+
/* @__PURE__ */ import_react45.default.createElement(
|
|
8086
8775
|
NumberField,
|
|
8087
8776
|
{
|
|
8088
8777
|
label: recognition.maxUtterance.label(),
|
|
@@ -8097,15 +8786,15 @@ function SilenceDetectionSettings({ settings, updateSettings }) {
|
|
|
8097
8786
|
}
|
|
8098
8787
|
}
|
|
8099
8788
|
),
|
|
8100
|
-
/* @__PURE__ */
|
|
8101
|
-
/* @__PURE__ */
|
|
8789
|
+
/* @__PURE__ */ import_react45.default.createElement("small", null, recognition.maxUtterance.help()),
|
|
8790
|
+
/* @__PURE__ */ import_react45.default.createElement(
|
|
8102
8791
|
"div",
|
|
8103
8792
|
{
|
|
8104
8793
|
className: "dlv-preset-group",
|
|
8105
8794
|
role: "radiogroup",
|
|
8106
8795
|
"aria-label": recognition.silenceDetection.pauseLabel()
|
|
8107
8796
|
},
|
|
8108
|
-
[...Object.keys(voiceDetectionPresets), "custom"].map((value) => /* @__PURE__ */
|
|
8797
|
+
[...Object.keys(voiceDetectionPresets), "custom"].map((value) => /* @__PURE__ */ import_react45.default.createElement("label", { key: value, className: "dlv-preset" }, /* @__PURE__ */ import_react45.default.createElement(
|
|
8109
8798
|
"input",
|
|
8110
8799
|
{
|
|
8111
8800
|
type: "radio",
|
|
@@ -8114,9 +8803,9 @@ function SilenceDetectionSettings({ settings, updateSettings }) {
|
|
|
8114
8803
|
checked: selected === value,
|
|
8115
8804
|
onChange: () => updateSettings({ voiceDetectionPreset: value })
|
|
8116
8805
|
}
|
|
8117
|
-
), /* @__PURE__ */
|
|
8806
|
+
), /* @__PURE__ */ import_react45.default.createElement("span", null, /* @__PURE__ */ import_react45.default.createElement("strong", null, recognition.presets[value].label()), /* @__PURE__ */ import_react45.default.createElement("small", null, recognition.presets[value].description()))))
|
|
8118
8807
|
),
|
|
8119
|
-
selected === "custom" && /* @__PURE__ */
|
|
8808
|
+
selected === "custom" && /* @__PURE__ */ import_react45.default.createElement(import_react45.default.Fragment, null, /* @__PURE__ */ import_react45.default.createElement(
|
|
8120
8809
|
NumberField,
|
|
8121
8810
|
{
|
|
8122
8811
|
label: recognition.silenceDetection.customLabel(),
|
|
@@ -8130,19 +8819,102 @@ function SilenceDetectionSettings({ settings, updateSettings }) {
|
|
|
8130
8819
|
updateSettings({ voiceDetectionCustomSilenceMs: value });
|
|
8131
8820
|
}
|
|
8132
8821
|
}
|
|
8133
|
-
), /* @__PURE__ */
|
|
8134
|
-
/* @__PURE__ */
|
|
8822
|
+
), /* @__PURE__ */ import_react45.default.createElement("small", null, recognition.silenceDetection.customHelp())),
|
|
8823
|
+
/* @__PURE__ */ import_react45.default.createElement("p", { className: "dlv-vad-summary" }, recognition.silenceDetection.duration({
|
|
8135
8824
|
milliseconds: voiceDetectionSilenceMs(settings)
|
|
8136
8825
|
}))
|
|
8137
8826
|
);
|
|
8138
8827
|
}
|
|
8139
8828
|
|
|
8140
8829
|
// src/modules/settings/sections/recognition/VoiceCommandSettings.tsx
|
|
8141
|
-
var
|
|
8830
|
+
var import_react47 = __toESM(require("react"), 1);
|
|
8831
|
+
|
|
8832
|
+
// src/shared/design-system/forms/PhraseField.tsx
|
|
8833
|
+
var import_react46 = __toESM(require("react"), 1);
|
|
8834
|
+
function PhraseField({
|
|
8835
|
+
label,
|
|
8836
|
+
value,
|
|
8837
|
+
disabled,
|
|
8838
|
+
onCommit,
|
|
8839
|
+
addLabel,
|
|
8840
|
+
removeLabel
|
|
8841
|
+
}) {
|
|
8842
|
+
const id2 = import_react46.default.useId();
|
|
8843
|
+
const [draft, setDraft] = import_react46.default.useState("");
|
|
8844
|
+
const [phrases2, setPhrases] = import_react46.default.useState(
|
|
8845
|
+
() => value.split(/[,\r\n]+/).map((s) => s.trim()).filter(Boolean)
|
|
8846
|
+
);
|
|
8847
|
+
const editing = import_react46.default.useRef(false);
|
|
8848
|
+
import_react46.default.useEffect(() => {
|
|
8849
|
+
if (!editing.current)
|
|
8850
|
+
setPhrases(
|
|
8851
|
+
value.split(/[,\r\n]+/).map((s) => s.trim()).filter(Boolean)
|
|
8852
|
+
);
|
|
8853
|
+
}, [value]);
|
|
8854
|
+
const commit = (raw = draft) => {
|
|
8855
|
+
const additions = raw.split(/[,\r\n]+/).map((s) => s.trim()).filter(Boolean);
|
|
8856
|
+
if (!additions.length) {
|
|
8857
|
+
setDraft("");
|
|
8858
|
+
return;
|
|
8859
|
+
}
|
|
8860
|
+
const next = [...phrases2, ...additions];
|
|
8861
|
+
if (next.join(", ").length > 1e3) return;
|
|
8862
|
+
setPhrases(next);
|
|
8863
|
+
setDraft("");
|
|
8864
|
+
onCommit(next.join(", "));
|
|
8865
|
+
};
|
|
8866
|
+
return /* @__PURE__ */ import_react46.default.createElement("div", { className: "dlv-phrase-field" }, /* @__PURE__ */ import_react46.default.createElement("label", { id: id2, htmlFor: id2 + "-input" }, label), /* @__PURE__ */ import_react46.default.createElement("div", { className: "dlv-phrase-box", "aria-disabled": disabled }, phrases2.map((phrase, index) => /* @__PURE__ */ import_react46.default.createElement("span", { className: "dlv-phrase", key: index }, /* @__PURE__ */ import_react46.default.createElement("span", null, phrase), /* @__PURE__ */ import_react46.default.createElement(
|
|
8867
|
+
"button",
|
|
8868
|
+
{
|
|
8869
|
+
type: "button",
|
|
8870
|
+
disabled,
|
|
8871
|
+
"aria-label": removeLabel + ": " + phrase,
|
|
8872
|
+
onClick: () => {
|
|
8873
|
+
const next = phrases2.filter((_2, i) => i !== index);
|
|
8874
|
+
setPhrases(next);
|
|
8875
|
+
onCommit(next.join(", "));
|
|
8876
|
+
}
|
|
8877
|
+
},
|
|
8878
|
+
"\xD7"
|
|
8879
|
+
))), /* @__PURE__ */ import_react46.default.createElement(
|
|
8880
|
+
"input",
|
|
8881
|
+
{
|
|
8882
|
+
id: id2 + "-input",
|
|
8883
|
+
"aria-labelledby": id2,
|
|
8884
|
+
placeholder: addLabel,
|
|
8885
|
+
value: draft,
|
|
8886
|
+
disabled,
|
|
8887
|
+
maxLength: 1e3,
|
|
8888
|
+
onFocus: () => {
|
|
8889
|
+
editing.current = true;
|
|
8890
|
+
},
|
|
8891
|
+
onInput: (e) => setDraft(e.currentTarget.value),
|
|
8892
|
+
onChange: (e) => setDraft(e.target.value),
|
|
8893
|
+
onBlur: () => {
|
|
8894
|
+
editing.current = false;
|
|
8895
|
+
commit();
|
|
8896
|
+
},
|
|
8897
|
+
onKeyDown: (e) => {
|
|
8898
|
+
if (e.nativeEvent.isComposing) return;
|
|
8899
|
+
if (e.key === "Enter" || e.key === ",") {
|
|
8900
|
+
e.preventDefault();
|
|
8901
|
+
commit();
|
|
8902
|
+
}
|
|
8903
|
+
if (e.key === "Escape") {
|
|
8904
|
+
e.preventDefault();
|
|
8905
|
+
e.stopPropagation();
|
|
8906
|
+
setDraft("");
|
|
8907
|
+
}
|
|
8908
|
+
}
|
|
8909
|
+
}
|
|
8910
|
+
)));
|
|
8911
|
+
}
|
|
8912
|
+
|
|
8913
|
+
// src/modules/settings/sections/recognition/VoiceCommandSettings.tsx
|
|
8142
8914
|
var COMMANDS = [
|
|
8143
8915
|
["send", "voiceCommandSend", "send message, send it"],
|
|
8144
8916
|
["queue", "voiceCommandQueue", "queue message, queue it"],
|
|
8145
|
-
["
|
|
8917
|
+
["end", "voiceCommandEnd", "end conversation, stop conversation"],
|
|
8146
8918
|
["mute", "voiceCommandMute", "mute microphone, stop listening"],
|
|
8147
8919
|
["resume", "voiceCommandResume", "resume listening, unmute microphone"],
|
|
8148
8920
|
["stopSpeech", "voiceCommandStopSpeaking", "stop talking, stop speaking, shut up"],
|
|
@@ -8151,126 +8923,216 @@ var COMMANDS = [
|
|
|
8151
8923
|
function VoiceCommandSettings({ settings, updateSettings }) {
|
|
8152
8924
|
const { scoped: recognition } = useLanguage((ctx) => ctx.recognition);
|
|
8153
8925
|
const enabled = settings.voiceCommandsEnabled !== false;
|
|
8154
|
-
return /* @__PURE__ */
|
|
8155
|
-
|
|
8926
|
+
return /* @__PURE__ */ import_react47.default.createElement(
|
|
8927
|
+
SettingsSection,
|
|
8156
8928
|
{
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
}
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8929
|
+
title: recognition.commands.title(),
|
|
8930
|
+
icon: "commands",
|
|
8931
|
+
defaultOpen: false
|
|
8932
|
+
},
|
|
8933
|
+
/* @__PURE__ */ import_react47.default.createElement(
|
|
8934
|
+
CheckboxField,
|
|
8935
|
+
{
|
|
8936
|
+
label: recognition.commands.enabled(),
|
|
8937
|
+
hint: recognition.voiceCommands.help(),
|
|
8938
|
+
checked: enabled,
|
|
8939
|
+
onChange: (event) => updateSettings({ voiceCommandsEnabled: event.target.checked })
|
|
8940
|
+
}
|
|
8941
|
+
),
|
|
8942
|
+
COMMANDS.map(([label, key, fallback]) => /* @__PURE__ */ import_react47.default.createElement(
|
|
8943
|
+
PhraseField,
|
|
8944
|
+
{
|
|
8945
|
+
key,
|
|
8946
|
+
addLabel: recognition.commands.addPhrase(),
|
|
8947
|
+
removeLabel: recognition.commands.removePhrase(),
|
|
8948
|
+
label: recognition.commands[label](),
|
|
8949
|
+
value: settings[key] ?? fallback,
|
|
8950
|
+
disabled: !enabled,
|
|
8951
|
+
onCommit: (value) => updateSettings({ [key]: value })
|
|
8952
|
+
}
|
|
8953
|
+
))
|
|
8954
|
+
);
|
|
8173
8955
|
}
|
|
8174
8956
|
|
|
8175
8957
|
// src/modules/settings/sections/recognition/RecognitionStatus.tsx
|
|
8176
|
-
var
|
|
8958
|
+
var import_react48 = __toESM(require("react"), 1);
|
|
8177
8959
|
function RecognitionStatus({ capabilities = {} }) {
|
|
8178
8960
|
const { scoped: recognition } = useLanguage((ctx) => ctx.recognition);
|
|
8179
|
-
return /* @__PURE__ */
|
|
8961
|
+
return /* @__PURE__ */ import_react48.default.createElement(import_react48.default.Fragment, null, capabilities.capture?.supported === false ? /* @__PURE__ */ import_react48.default.createElement("p", { role: "status" }, recognition.microphone.failure({ reason: capabilities.capture.reason || "" })) : capabilities.capture?.permission === "prompt" ? /* @__PURE__ */ import_react48.default.createElement("p", { role: "status" }, recognition.microphone.permissionHelp()) : null, capabilities.recognition?.supported === false && /* @__PURE__ */ import_react48.default.createElement("p", { role: "status" }, capabilities.recognition.reason));
|
|
8962
|
+
}
|
|
8963
|
+
|
|
8964
|
+
// src/modules/settings/sections/conversation/MeetingSourceSettings.tsx
|
|
8965
|
+
var import_react49 = __toESM(require("react"), 1);
|
|
8966
|
+
function MeetingSourceSettings({ settings, updateSettings }) {
|
|
8967
|
+
const { scoped: language } = useLanguage((ctx) => ctx.settings);
|
|
8968
|
+
const { scoped: meeting } = useLanguage((ctx) => ctx.meeting);
|
|
8969
|
+
const names = language.sourceNames;
|
|
8970
|
+
return /* @__PURE__ */ import_react49.default.createElement(SettingsSection, { title: meeting.title(), icon: "meeting", defaultOpen: false }, /* @__PURE__ */ import_react49.default.createElement("p", null, names.help()), /* @__PURE__ */ import_react49.default.createElement(
|
|
8971
|
+
DraftField,
|
|
8972
|
+
{
|
|
8973
|
+
label: names.microphone(),
|
|
8974
|
+
value: settings.microphoneSourceName,
|
|
8975
|
+
maxLength: 80,
|
|
8976
|
+
onCommit: (microphoneSourceName) => updateSettings({ microphoneSourceName })
|
|
8977
|
+
}
|
|
8978
|
+
), /* @__PURE__ */ import_react49.default.createElement(
|
|
8979
|
+
DraftField,
|
|
8980
|
+
{
|
|
8981
|
+
label: names.shared(),
|
|
8982
|
+
value: settings.sharedSourceName,
|
|
8983
|
+
maxLength: 80,
|
|
8984
|
+
onCommit: (sharedSourceName) => updateSettings({ sharedSourceName })
|
|
8985
|
+
}
|
|
8986
|
+
));
|
|
8180
8987
|
}
|
|
8181
8988
|
|
|
8182
8989
|
// src/modules/settings/sections/recognition/RecognitionSettingsSection.tsx
|
|
8183
8990
|
function RecognitionSettingsSection(props) {
|
|
8184
8991
|
const { scoped: settingsLanguage } = useLanguage((ctx) => ctx.settings);
|
|
8185
|
-
return /* @__PURE__ */
|
|
8992
|
+
return /* @__PURE__ */ import_react50.default.createElement(SettingsCard, null, /* @__PURE__ */ import_react50.default.createElement("div", { className: "dlv-settings-card-body" }, /* @__PURE__ */ import_react50.default.createElement(RecognitionStatus, { ...props }), /* @__PURE__ */ import_react50.default.createElement(SettingsSection, { title: settingsLanguage.layout.transcription(), icon: "mic" }, /* @__PURE__ */ import_react50.default.createElement(RecognitionEngineSettings, { ...props })), /* @__PURE__ */ import_react50.default.createElement(MeetingSourceSettings, { ...props }), /* @__PURE__ */ import_react50.default.createElement(VoiceCommandSettings, { ...props }), /* @__PURE__ */ import_react50.default.createElement(SilenceDetectionSettings, { ...props }), /* @__PURE__ */ import_react50.default.createElement(RecognitionFilterSettings, { ...props })));
|
|
8186
8993
|
}
|
|
8187
8994
|
|
|
8188
8995
|
// src/modules/settings/sections/speak/OutputFilterSettings.tsx
|
|
8189
|
-
var
|
|
8996
|
+
var import_react51 = __toESM(require("react"), 1);
|
|
8190
8997
|
function OutputFilterSettings({ settings, updateSettings }) {
|
|
8191
8998
|
const { scoped: speak } = useLanguage((ctx) => ctx.speak);
|
|
8192
8999
|
const enabled = settings.outputCodeFilterEnabled !== false;
|
|
8193
|
-
return /* @__PURE__ */
|
|
8194
|
-
|
|
8195
|
-
{
|
|
8196
|
-
label: speak.filters.code.enabled(),
|
|
8197
|
-
checked: enabled,
|
|
8198
|
-
onChange: (event) => updateSettings({ outputCodeFilterEnabled: event.target.checked })
|
|
8199
|
-
}
|
|
8200
|
-
), /* @__PURE__ */ import_react47.default.createElement(
|
|
8201
|
-
NumberField,
|
|
9000
|
+
return /* @__PURE__ */ import_react51.default.createElement(
|
|
9001
|
+
SettingsSection,
|
|
8202
9002
|
{
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
9003
|
+
title: speak.filters.code.enabled(),
|
|
9004
|
+
icon: "filter",
|
|
9005
|
+
defaultOpen: false
|
|
9006
|
+
},
|
|
9007
|
+
/* @__PURE__ */ import_react51.default.createElement(
|
|
9008
|
+
CheckboxField,
|
|
9009
|
+
{
|
|
9010
|
+
label: speak.filters.code.enabled(),
|
|
9011
|
+
checked: enabled,
|
|
9012
|
+
onChange: (event) => updateSettings({ outputCodeFilterEnabled: event.target.checked })
|
|
8212
9013
|
}
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
9014
|
+
),
|
|
9015
|
+
/* @__PURE__ */ import_react51.default.createElement(
|
|
9016
|
+
NumberField,
|
|
9017
|
+
{
|
|
9018
|
+
label: speak.filters.code.maxLines(),
|
|
9019
|
+
min: 0,
|
|
9020
|
+
max: 100,
|
|
9021
|
+
value: settings.outputCodeMaxLines ?? 5,
|
|
9022
|
+
disabled: !enabled,
|
|
9023
|
+
onCommit: (raw) => {
|
|
9024
|
+
const value = Number(raw);
|
|
9025
|
+
if (Number.isInteger(value) && value >= 0 && value <= 100)
|
|
9026
|
+
updateSettings({ outputCodeMaxLines: value });
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
9029
|
+
),
|
|
9030
|
+
/* @__PURE__ */ import_react51.default.createElement(
|
|
9031
|
+
TextField,
|
|
9032
|
+
{
|
|
9033
|
+
label: speak.filters.code.replacement(),
|
|
9034
|
+
value: settings.outputCodeNotice ?? speak.filters.code.notice(),
|
|
9035
|
+
disabled: !enabled,
|
|
9036
|
+
onCommit: (value) => updateSettings({ outputCodeNotice: value })
|
|
9037
|
+
}
|
|
9038
|
+
)
|
|
9039
|
+
);
|
|
8223
9040
|
}
|
|
8224
9041
|
|
|
8225
9042
|
// src/modules/settings/sections/speak/SpeakSettingsSection.tsx
|
|
8226
|
-
var
|
|
9043
|
+
var import_react54 = __toESM(require("react"), 1);
|
|
8227
9044
|
|
|
8228
9045
|
// src/modules/settings/sections/speak/SpeechEngineSettings.tsx
|
|
8229
|
-
var
|
|
8230
|
-
|
|
9046
|
+
var import_react52 = __toESM(require("react"), 1);
|
|
9047
|
+
|
|
9048
|
+
// src/modules/settings/models/browserVoiceSelection.ts
|
|
9049
|
+
function baseLanguage(language) {
|
|
9050
|
+
return (language ?? "").trim().replace(/_/g, "-").split("-")[0].toLowerCase();
|
|
9051
|
+
}
|
|
9052
|
+
function isNaturalVoice(voice) {
|
|
9053
|
+
return /\bnatural\b/i.test(voice.name);
|
|
9054
|
+
}
|
|
9055
|
+
function rankBrowserVoices(voices, browserLanguage) {
|
|
9056
|
+
const language = baseLanguage(browserLanguage);
|
|
9057
|
+
const matches = (voice) => Boolean(language) && baseLanguage(voice.lang) === language;
|
|
9058
|
+
return [...voices].sort(
|
|
9059
|
+
(a, b) => Number(isNaturalVoice(b)) - Number(isNaturalVoice(a)) || Number(matches(b)) - Number(matches(a)) || a.name.localeCompare(b.name)
|
|
9060
|
+
);
|
|
9061
|
+
}
|
|
9062
|
+
function groupBrowserVoices(voices, browserLanguage) {
|
|
9063
|
+
const groups = /* @__PURE__ */ new Map();
|
|
9064
|
+
for (const voice of rankBrowserVoices(voices, browserLanguage)) {
|
|
9065
|
+
const language = baseLanguage(voice.lang);
|
|
9066
|
+
const group = groups.get(language) ?? [];
|
|
9067
|
+
group.push(voice);
|
|
9068
|
+
groups.set(language, group);
|
|
9069
|
+
}
|
|
9070
|
+
const preferredLanguage = baseLanguage(browserLanguage);
|
|
9071
|
+
return [...groups].map(([language, voices2]) => ({ language, voices: voices2 })).sort(
|
|
9072
|
+
(a, b) => Number(Boolean(preferredLanguage) && b.language === preferredLanguage) - Number(Boolean(preferredLanguage) && a.language === preferredLanguage) || Number(!a.language) - Number(!b.language) || a.language.localeCompare(b.language)
|
|
9073
|
+
);
|
|
9074
|
+
}
|
|
9075
|
+
function preferredBrowserVoice(voices, browserLanguage) {
|
|
9076
|
+
const voice = rankBrowserVoices(voices, browserLanguage).find(isNaturalVoice);
|
|
9077
|
+
return voice ? voice.voiceURI || voice.name : void 0;
|
|
9078
|
+
}
|
|
9079
|
+
function speechEngineSelectionPatch(currentEngine, nextEngine, voices, browserLanguage) {
|
|
9080
|
+
const voice = nextEngine === "browser" && currentEngine !== "browser" ? preferredBrowserVoice(voices, browserLanguage) : void 0;
|
|
9081
|
+
return { engine: nextEngine, ...voice === void 0 ? {} : { voice } };
|
|
9082
|
+
}
|
|
9083
|
+
|
|
9084
|
+
// src/modules/settings/sections/speak/SpeechEngineSettings.tsx
|
|
9085
|
+
function SpeechEngineSettings({
|
|
9086
|
+
settings,
|
|
9087
|
+
capabilities,
|
|
9088
|
+
updateSettings,
|
|
9089
|
+
hostPlatform
|
|
9090
|
+
}) {
|
|
9091
|
+
const locale = typeof window === "undefined" ? "" : window.navigator.language;
|
|
8231
9092
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
8232
9093
|
const { scoped: speak } = useLanguage((ctx) => ctx.speak);
|
|
8233
9094
|
const engine = settings.engine || "browser";
|
|
8234
9095
|
const browserVoices = capabilities?.browser?.voices || [];
|
|
8235
|
-
|
|
9096
|
+
const capability = capabilities?.[engine];
|
|
9097
|
+
const defaultBrowserVoice = preferredBrowserVoice(browserVoices, locale);
|
|
9098
|
+
const sortedBrowserOptions = groupBrowserVoices(browserVoices, locale).map((group) => ({
|
|
9099
|
+
label: group.language || commons.unknownLanguage(),
|
|
9100
|
+
options: group.voices.map((voice) => ({
|
|
9101
|
+
value: voice.voiceURI || voice.name,
|
|
9102
|
+
label: (voice.voiceURI || voice.name) === defaultBrowserVoice ? voice.name + " (" + speak.browser.defaultVoice() + ")" : voice.name
|
|
9103
|
+
}))
|
|
9104
|
+
}));
|
|
9105
|
+
return /* @__PURE__ */ import_react52.default.createElement(import_react52.default.Fragment, null, /* @__PURE__ */ import_react52.default.createElement(
|
|
8236
9106
|
SelectField,
|
|
8237
9107
|
{
|
|
8238
9108
|
label: speak.engine.label(),
|
|
8239
9109
|
value: engine,
|
|
8240
|
-
options:
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
label: speak.browser.label(),
|
|
8254
|
-
disabled: capabilities?.browser?.supported === false
|
|
8255
|
-
}
|
|
8256
|
-
],
|
|
8257
|
-
onChange: (event) => updateSettings({ engine: event.target.value })
|
|
9110
|
+
options: speakingEngineOrder(hostPlatform).map((value) => ({
|
|
9111
|
+
value,
|
|
9112
|
+
label: {
|
|
9113
|
+
say: speak.macos.label(),
|
|
9114
|
+
browser: speak.browser.label(),
|
|
9115
|
+
"qwen-http": speak.qwen.label()
|
|
9116
|
+
}[value]
|
|
9117
|
+
})),
|
|
9118
|
+
onChange: (event) => {
|
|
9119
|
+
updateSettings(
|
|
9120
|
+
speechEngineSelectionPatch(engine, event.target.value, browserVoices, locale)
|
|
9121
|
+
);
|
|
9122
|
+
}
|
|
8258
9123
|
}
|
|
8259
|
-
), engine === "browser" && /* @__PURE__ */
|
|
9124
|
+
), engine === "browser" && /* @__PURE__ */ import_react52.default.createElement(
|
|
8260
9125
|
SelectField,
|
|
8261
9126
|
{
|
|
8262
9127
|
label: speak.browser.voice(),
|
|
8263
9128
|
value: settings.voice || "",
|
|
8264
9129
|
options: [
|
|
8265
9130
|
{ value: "", label: commons.systemDefault() },
|
|
8266
|
-
...
|
|
8267
|
-
value: voice.voiceURI || voice.name,
|
|
8268
|
-
label: voice.name
|
|
8269
|
-
}))
|
|
9131
|
+
...sortedBrowserOptions
|
|
8270
9132
|
],
|
|
8271
9133
|
onChange: (event) => updateSettings({ voice: event.target.value })
|
|
8272
9134
|
}
|
|
8273
|
-
), engine === "say" && /* @__PURE__ */
|
|
9135
|
+
), engine === "say" && /* @__PURE__ */ import_react52.default.createElement(import_react52.default.Fragment, null, /* @__PURE__ */ import_react52.default.createElement(
|
|
8274
9136
|
TextField,
|
|
8275
9137
|
{
|
|
8276
9138
|
label: speak.macos.voice(),
|
|
@@ -8278,7 +9140,7 @@ function SpeechEngineSettings({ settings, capabilities, updateSettings }) {
|
|
|
8278
9140
|
placeholder: commons.systemDefault(),
|
|
8279
9141
|
onCommit: (value) => updateSettings({ voice: value.trim() })
|
|
8280
9142
|
}
|
|
8281
|
-
), /* @__PURE__ */
|
|
9143
|
+
), /* @__PURE__ */ import_react52.default.createElement("p", { className: "dlv-setting-description" }, speak.macos.voiceHelp())), engine === "qwen-http" && /* @__PURE__ */ import_react52.default.createElement(
|
|
8282
9144
|
SelectField,
|
|
8283
9145
|
{
|
|
8284
9146
|
label: speak.qwen.voice(),
|
|
@@ -8286,31 +9148,42 @@ function SpeechEngineSettings({ settings, capabilities, updateSettings }) {
|
|
|
8286
9148
|
options: qwenVoices,
|
|
8287
9149
|
onChange: (event) => updateSettings({ voice: event.target.value })
|
|
8288
9150
|
}
|
|
8289
|
-
), /* @__PURE__ */
|
|
9151
|
+
), /* @__PURE__ */ import_react52.default.createElement("label", null, speak.volume.label(), " (", Math.round((settings.volume ?? 1) * 100), "%)", /* @__PURE__ */ import_react52.default.createElement(
|
|
9152
|
+
"input",
|
|
9153
|
+
{
|
|
9154
|
+
type: "range",
|
|
9155
|
+
min: 0,
|
|
9156
|
+
max: 1,
|
|
9157
|
+
step: 0.01,
|
|
9158
|
+
value: settings.volume ?? 1,
|
|
9159
|
+
"aria-label": speak.volume.label(),
|
|
9160
|
+
onInput: (event) => updateSettings({ volume: Number(event.currentTarget.value) })
|
|
9161
|
+
}
|
|
9162
|
+
)), /* @__PURE__ */ import_react52.default.createElement("p", { className: "dlv-setting-description" }, speak.volume.help()), /* @__PURE__ */ import_react52.default.createElement("div", { className: "dlv-field-pair" }, /* @__PURE__ */ import_react52.default.createElement(
|
|
8290
9163
|
NumberField,
|
|
8291
9164
|
{
|
|
8292
|
-
label: speak.rate.label(),
|
|
9165
|
+
label: speak.rate.label() + " (\xD7)",
|
|
8293
9166
|
min: 0.1,
|
|
8294
9167
|
max: 3,
|
|
8295
9168
|
step: 0.1,
|
|
8296
9169
|
value: settings.rate ?? 1,
|
|
8297
9170
|
onCommit: (value) => updateSettings({ rate: Number(value) })
|
|
8298
9171
|
}
|
|
8299
|
-
), /* @__PURE__ */
|
|
9172
|
+
), /* @__PURE__ */ import_react52.default.createElement(
|
|
8300
9173
|
NumberField,
|
|
8301
9174
|
{
|
|
8302
|
-
label: speak.segmentGap.label(),
|
|
9175
|
+
label: speak.segmentGap.label() + " (ms)",
|
|
8303
9176
|
min: 0,
|
|
8304
9177
|
max: 2e3,
|
|
8305
9178
|
step: 50,
|
|
8306
9179
|
value: settings.segmentGapMs ?? 400,
|
|
8307
9180
|
onCommit: (value) => updateSettings({ segmentGapMs: Number(value) })
|
|
8308
9181
|
}
|
|
8309
|
-
),
|
|
9182
|
+
)), capability?.supported === false && /* @__PURE__ */ import_react52.default.createElement("p", { role: "status" }, capability.reason || commons.engine.failure()));
|
|
8310
9183
|
}
|
|
8311
9184
|
|
|
8312
9185
|
// src/modules/settings/sections/speak/SpeechAdvancedSettings.tsx
|
|
8313
|
-
var
|
|
9186
|
+
var import_react53 = __toESM(require("react"), 1);
|
|
8314
9187
|
function SpeechAdvancedSettings({
|
|
8315
9188
|
controller,
|
|
8316
9189
|
settings,
|
|
@@ -8328,7 +9201,7 @@ function SpeechAdvancedSettings({
|
|
|
8328
9201
|
commons.systemDefault(),
|
|
8329
9202
|
speak.output.fallbackName()
|
|
8330
9203
|
);
|
|
8331
|
-
return /* @__PURE__ */
|
|
9204
|
+
return /* @__PURE__ */ import_react53.default.createElement(import_react53.default.Fragment, null, settings.engine !== "say" ? /* @__PURE__ */ import_react53.default.createElement(
|
|
8332
9205
|
SelectField,
|
|
8333
9206
|
{
|
|
8334
9207
|
label: speak.output.device(),
|
|
@@ -8336,14 +9209,14 @@ function SpeechAdvancedSettings({
|
|
|
8336
9209
|
options: outputOptions,
|
|
8337
9210
|
onChange: (event) => updateSettings({ outputDeviceId: event.target.value })
|
|
8338
9211
|
}
|
|
8339
|
-
) : /* @__PURE__ */
|
|
9212
|
+
) : /* @__PURE__ */ import_react53.default.createElement("p", { className: "dlv-setting-description" }, speak.macos.outputHelp()), settings.engine === "qwen-http" && /* @__PURE__ */ import_react53.default.createElement(SettingsSubcard, { title: speak.qwen.connection(), icon: "link" }, /* @__PURE__ */ import_react53.default.createElement(QwenSettings, { controller })), /* @__PURE__ */ import_react53.default.createElement(SettingsSubcard, { title: speak.agentContext.label(), icon: "settings" }, /* @__PURE__ */ import_react53.default.createElement(
|
|
8340
9213
|
CheckboxField,
|
|
8341
9214
|
{
|
|
8342
9215
|
label: speak.agentContext.enabled(),
|
|
8343
9216
|
checked: settings.agentVoiceContextEnabled !== false,
|
|
8344
9217
|
onChange: (event) => updateSettings({ agentVoiceContextEnabled: event.target.checked })
|
|
8345
9218
|
}
|
|
8346
|
-
), /* @__PURE__ */
|
|
9219
|
+
), /* @__PURE__ */ import_react53.default.createElement(
|
|
8347
9220
|
TextAreaField,
|
|
8348
9221
|
{
|
|
8349
9222
|
label: speak.agentContext.label(),
|
|
@@ -8351,30 +9224,30 @@ function SpeechAdvancedSettings({
|
|
|
8351
9224
|
disabled: settings.agentVoiceContextEnabled === false,
|
|
8352
9225
|
onCommit: (value) => updateSettings({ agentVoiceContext: value })
|
|
8353
9226
|
}
|
|
8354
|
-
), /* @__PURE__ */
|
|
9227
|
+
), /* @__PURE__ */ import_react53.default.createElement(
|
|
8355
9228
|
"button",
|
|
8356
9229
|
{
|
|
8357
9230
|
type: "button",
|
|
8358
9231
|
onClick: () => updateSettings({ agentVoiceContext: defaultAgentVoiceContext })
|
|
8359
9232
|
},
|
|
8360
9233
|
speak.agentContext.restore()
|
|
8361
|
-
)), /* @__PURE__ */
|
|
9234
|
+
)), /* @__PURE__ */ import_react53.default.createElement("p", null, speak.engine.playbackHelp()), /* @__PURE__ */ import_react53.default.createElement("div", { className: "dlv-settings-actions" }, /* @__PURE__ */ import_react53.default.createElement("button", { type: "button", onClick: () => invoke("speak", speak.output.testPhrase()) }, speak.output.test()), speaking && /* @__PURE__ */ import_react53.default.createElement("button", { type: "button", onClick: () => invoke("stopSpeech") }, speak.output.stopTest()), /* @__PURE__ */ import_react53.default.createElement("button", { type: "button", onClick: () => invoke("refreshCapabilities", { localOnly: true }) }, settingsLanguage.engine.refresh())));
|
|
8362
9235
|
}
|
|
8363
9236
|
|
|
8364
9237
|
// src/modules/settings/sections/speak/SpeakSettingsSection.tsx
|
|
8365
9238
|
function SpeakSettingsSection(props) {
|
|
8366
9239
|
const { scoped: settingsLanguage } = useLanguage((ctx) => ctx.settings);
|
|
8367
|
-
return /* @__PURE__ */
|
|
9240
|
+
return /* @__PURE__ */ import_react54.default.createElement(SettingsCard, null, /* @__PURE__ */ import_react54.default.createElement("div", { className: "dlv-settings-card-body" }, /* @__PURE__ */ import_react54.default.createElement(SettingsSection, { title: settingsLanguage.layout.voice(), icon: "speaker" }, /* @__PURE__ */ import_react54.default.createElement(SpeechEngineSettings, { ...props })), /* @__PURE__ */ import_react54.default.createElement(SettingsSection, { title: settingsLanguage.layout.playback(), icon: "play" }, /* @__PURE__ */ import_react54.default.createElement(SpeechAdvancedSettings, { ...props })), /* @__PURE__ */ import_react54.default.createElement(OutputFilterSettings, { ...props })));
|
|
8368
9241
|
}
|
|
8369
9242
|
|
|
8370
9243
|
// src/modules/settings/components/SettingsHeader.tsx
|
|
8371
|
-
var
|
|
9244
|
+
var import_react57 = __toESM(require("react"), 1);
|
|
8372
9245
|
|
|
8373
9246
|
// src/modules/settings/components/VersionBadges.tsx
|
|
8374
|
-
var
|
|
9247
|
+
var import_react55 = __toESM(require("react"), 1);
|
|
8375
9248
|
function VersionBadges() {
|
|
8376
9249
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
8377
|
-
return /* @__PURE__ */
|
|
9250
|
+
return /* @__PURE__ */ import_react55.default.createElement("div", { className: "dlv-version-badges", "aria-label": commons.version.title() }, /* @__PURE__ */ import_react55.default.createElement(
|
|
8378
9251
|
"a",
|
|
8379
9252
|
{
|
|
8380
9253
|
className: "dlv-shields-badge",
|
|
@@ -8384,9 +9257,9 @@ function VersionBadges() {
|
|
|
8384
9257
|
"aria-label": commons.version.link({ version: CURRENT_VERSION }),
|
|
8385
9258
|
title: commons.version.label({ version: CURRENT_VERSION })
|
|
8386
9259
|
},
|
|
8387
|
-
/* @__PURE__ */
|
|
8388
|
-
/* @__PURE__ */
|
|
8389
|
-
), /* @__PURE__ */
|
|
9260
|
+
/* @__PURE__ */ import_react55.default.createElement("img", { src: LIVE_VOICE_BADGE_URL, alt: "" }),
|
|
9261
|
+
/* @__PURE__ */ import_react55.default.createElement("span", null, `v${CURRENT_VERSION}`)
|
|
9262
|
+
), /* @__PURE__ */ import_react55.default.createElement(
|
|
8390
9263
|
"a",
|
|
8391
9264
|
{
|
|
8392
9265
|
className: "dlv-shields-badge",
|
|
@@ -8396,32 +9269,32 @@ function VersionBadges() {
|
|
|
8396
9269
|
"aria-label": commons.version.compatibilityLink({ version: TESTED_DSH_VERSION }),
|
|
8397
9270
|
title: commons.version.compatibility({ version: TESTED_DSH_VERSION })
|
|
8398
9271
|
},
|
|
8399
|
-
/* @__PURE__ */
|
|
8400
|
-
/* @__PURE__ */
|
|
9272
|
+
/* @__PURE__ */ import_react55.default.createElement("img", { src: DSH_BADGE_URL, alt: "" }),
|
|
9273
|
+
/* @__PURE__ */ import_react55.default.createElement("span", null, `v${TESTED_DSH_VERSION}`)
|
|
8401
9274
|
));
|
|
8402
9275
|
}
|
|
8403
9276
|
|
|
8404
9277
|
// src/modules/settings/components/PluginUpdateAction.tsx
|
|
8405
|
-
var
|
|
9278
|
+
var import_react56 = __toESM(require("react"), 1);
|
|
8406
9279
|
function PluginUpdateAction({ updater, tag }) {
|
|
8407
9280
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
8408
9281
|
const text = commons.update;
|
|
8409
|
-
const state =
|
|
9282
|
+
const state = import_react56.default.useSyncExternalStore(
|
|
8410
9283
|
updater.subscribe,
|
|
8411
9284
|
updater.getSnapshot,
|
|
8412
9285
|
updater.getSnapshot
|
|
8413
9286
|
);
|
|
8414
|
-
const [open, setOpen] =
|
|
8415
|
-
const panelId =
|
|
8416
|
-
const trigger =
|
|
8417
|
-
const confirmButton =
|
|
8418
|
-
|
|
9287
|
+
const [open, setOpen] = import_react56.default.useState(false);
|
|
9288
|
+
const panelId = import_react56.default.useId();
|
|
9289
|
+
const trigger = import_react56.default.useRef(null);
|
|
9290
|
+
const confirmButton = import_react56.default.useRef(null);
|
|
9291
|
+
import_react56.default.useEffect(() => {
|
|
8419
9292
|
if (state.phase === "confirm") confirmButton.current?.focus();
|
|
8420
9293
|
}, [state.phase]);
|
|
8421
9294
|
const busy = state.phase === "checking" || state.phase === "installing";
|
|
8422
9295
|
const settled = ["restart", "done", "uncertain"].includes(state.phase);
|
|
8423
9296
|
const expanded = open || busy || settled || state.phase === "confirm";
|
|
8424
|
-
return /* @__PURE__ */
|
|
9297
|
+
return /* @__PURE__ */ import_react56.default.createElement("span", { className: "dlv-plugin-update" }, /* @__PURE__ */ import_react56.default.createElement(
|
|
8425
9298
|
"button",
|
|
8426
9299
|
{
|
|
8427
9300
|
type: "button",
|
|
@@ -8435,9 +9308,9 @@ function PluginUpdateAction({ updater, tag }) {
|
|
|
8435
9308
|
void updater.prepare(tag);
|
|
8436
9309
|
}
|
|
8437
9310
|
},
|
|
8438
|
-
/* @__PURE__ */
|
|
9311
|
+
/* @__PURE__ */ import_react56.default.createElement("span", { "aria-hidden": "true" }, "\u21BB "),
|
|
8439
9312
|
busy ? text.installing() : text.now()
|
|
8440
|
-
), expanded && /* @__PURE__ */
|
|
9313
|
+
), expanded && /* @__PURE__ */ import_react56.default.createElement("span", { id: panelId, className: "dlv-plugin-update-panel" }, state.phase === "confirm" ? /* @__PURE__ */ import_react56.default.createElement(import_react56.default.Fragment, null, /* @__PURE__ */ import_react56.default.createElement("span", { id: panelId + "-confirmation" }, text.confirm({ version: state.version })), /* @__PURE__ */ import_react56.default.createElement(
|
|
8441
9314
|
"button",
|
|
8442
9315
|
{
|
|
8443
9316
|
ref: confirmButton,
|
|
@@ -8446,7 +9319,7 @@ function PluginUpdateAction({ updater, tag }) {
|
|
|
8446
9319
|
onClick: () => void updater.confirm()
|
|
8447
9320
|
},
|
|
8448
9321
|
text.now()
|
|
8449
|
-
), /* @__PURE__ */
|
|
9322
|
+
), /* @__PURE__ */ import_react56.default.createElement(
|
|
8450
9323
|
"button",
|
|
8451
9324
|
{
|
|
8452
9325
|
type: "button",
|
|
@@ -8457,13 +9330,13 @@ function PluginUpdateAction({ updater, tag }) {
|
|
|
8457
9330
|
}
|
|
8458
9331
|
},
|
|
8459
9332
|
text.cancel()
|
|
8460
|
-
)) : /* @__PURE__ */
|
|
9333
|
+
)) : /* @__PURE__ */ import_react56.default.createElement(
|
|
8461
9334
|
"span",
|
|
8462
9335
|
{
|
|
8463
9336
|
role: state.phase === "failed" || state.phase === "uncertain" ? "alert" : "status"
|
|
8464
9337
|
},
|
|
8465
9338
|
state.phase === "restart" ? text.restart({ version: state.version }) : state.phase === "done" ? text.done({ version: state.version }) : state.problem ? text[state.problem]() : busy ? text.installing() : null
|
|
8466
|
-
), state.phase === "failed" && /* @__PURE__ */
|
|
9339
|
+
), state.phase === "failed" && /* @__PURE__ */ import_react56.default.createElement("button", { type: "button", onClick: () => setOpen(false) }, text.cancel())));
|
|
8467
9340
|
}
|
|
8468
9341
|
|
|
8469
9342
|
// src/modules/settings/components/SettingsHeader.tsx
|
|
@@ -8474,7 +9347,7 @@ function SettingsHeader({
|
|
|
8474
9347
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
8475
9348
|
const { scoped: settings } = useLanguage((ctx) => ctx.settings);
|
|
8476
9349
|
const { latestRelease, updateAvailable } = useReleaseStatus();
|
|
8477
|
-
return /* @__PURE__ */
|
|
9350
|
+
return /* @__PURE__ */ import_react57.default.createElement("div", { className: "dlv-settings-heading" }, /* @__PURE__ */ import_react57.default.createElement("h3", null, commons.pluginName()), /* @__PURE__ */ import_react57.default.createElement(VersionBadges, null), /* @__PURE__ */ import_react57.default.createElement("span", { className: "dlv-heading-divider", "aria-hidden": true }), updateAvailable && latestRelease ? /* @__PURE__ */ import_react57.default.createElement(import_react57.default.Fragment, null, pluginUpdate && /* @__PURE__ */ import_react57.default.createElement(PluginUpdateAction, { updater: pluginUpdate, tag: latestRelease.tag }), /* @__PURE__ */ import_react57.default.createElement(
|
|
8478
9351
|
"a",
|
|
8479
9352
|
{
|
|
8480
9353
|
className: "dlv-version-badge dlv-update-badge",
|
|
@@ -8484,9 +9357,9 @@ function SettingsHeader({
|
|
|
8484
9357
|
"aria-label": commons.update.link({ version: latestRelease.tag }),
|
|
8485
9358
|
title: commons.update.version({ version: latestRelease.tag })
|
|
8486
9359
|
},
|
|
8487
|
-
/* @__PURE__ */
|
|
9360
|
+
/* @__PURE__ */ import_react57.default.createElement("span", { className: "dlv-update-icon", "aria-hidden": true }, "\u2191"),
|
|
8488
9361
|
commons.update.label()
|
|
8489
|
-
), /* @__PURE__ */
|
|
9362
|
+
), /* @__PURE__ */ import_react57.default.createElement("span", { className: "dlv-heading-divider", "aria-hidden": true })) : null, /* @__PURE__ */ import_react57.default.createElement(
|
|
8490
9363
|
"a",
|
|
8491
9364
|
{
|
|
8492
9365
|
className: "dlv-version-badge dlv-star-badge",
|
|
@@ -8498,7 +9371,7 @@ function SettingsHeader({
|
|
|
8498
9371
|
},
|
|
8499
9372
|
"\u2605 ",
|
|
8500
9373
|
commons.repository.starLabel()
|
|
8501
|
-
), onClose ? /* @__PURE__ */
|
|
9374
|
+
), onClose ? /* @__PURE__ */ import_react57.default.createElement(IconButton, { icon: "close", label: settings.close(), onClick: onClose }) : null);
|
|
8502
9375
|
}
|
|
8503
9376
|
|
|
8504
9377
|
// src/modules/core/developerExtension.ts
|
|
@@ -8523,15 +9396,40 @@ function LiveVoiceSettings({
|
|
|
8523
9396
|
const { scoped: settingsLanguage } = useLanguage((ctx) => ctx.settings);
|
|
8524
9397
|
const state = useConversationController(controller);
|
|
8525
9398
|
const { invoke, error, clearError } = useConversationActions(controller);
|
|
8526
|
-
const [activeTab, setActiveTab] =
|
|
8527
|
-
const tabsId =
|
|
8528
|
-
const
|
|
9399
|
+
const [activeTab, setActiveTab] = import_react58.default.useState("conversation");
|
|
9400
|
+
const tabsId = import_react58.default.useId();
|
|
9401
|
+
const container = import_react58.default.useRef(null);
|
|
9402
|
+
import_react58.default.useLayoutEffect(() => {
|
|
9403
|
+
const element = container.current;
|
|
9404
|
+
if (!element) return;
|
|
9405
|
+
let viewport = element.parentElement;
|
|
9406
|
+
while (viewport && !/(auto|scroll)/.test(window.getComputedStyle(viewport).overflowY))
|
|
9407
|
+
viewport = viewport.parentElement;
|
|
9408
|
+
if (!viewport) return;
|
|
9409
|
+
const host = viewport;
|
|
9410
|
+
const resize = () => {
|
|
9411
|
+
const style = window.getComputedStyle(host);
|
|
9412
|
+
element.style.height = Math.max(
|
|
9413
|
+
0,
|
|
9414
|
+
host.clientHeight - parseFloat(style.paddingTop || "0") - parseFloat(style.paddingBottom || "0")
|
|
9415
|
+
) + "px";
|
|
9416
|
+
};
|
|
9417
|
+
resize();
|
|
9418
|
+
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(resize) : null;
|
|
9419
|
+
observer?.observe(host);
|
|
9420
|
+
window.addEventListener("resize", resize);
|
|
9421
|
+
return () => {
|
|
9422
|
+
observer?.disconnect();
|
|
9423
|
+
window.removeEventListener("resize", resize);
|
|
9424
|
+
};
|
|
9425
|
+
}, []);
|
|
9426
|
+
const developer = import_react58.default.useSyncExternalStore(
|
|
8529
9427
|
subscribeDeveloperExtension,
|
|
8530
9428
|
readDeveloperExtension,
|
|
8531
9429
|
() => null
|
|
8532
9430
|
);
|
|
8533
9431
|
const Developer = developer?.component;
|
|
8534
|
-
const selectedTab = activeTab
|
|
9432
|
+
const selectedTab = activeTab;
|
|
8535
9433
|
const tabs = [
|
|
8536
9434
|
{ id: "speech", label: settingsLanguage.tabs.speak(), icon: "speaker" },
|
|
8537
9435
|
{
|
|
@@ -8542,50 +9440,62 @@ function LiveVoiceSettings({
|
|
|
8542
9440
|
{
|
|
8543
9441
|
id: "conversation",
|
|
8544
9442
|
label: settingsLanguage.tabs.conversation(),
|
|
8545
|
-
icon: "
|
|
9443
|
+
icon: "conversation"
|
|
8546
9444
|
}
|
|
8547
9445
|
];
|
|
8548
|
-
if (developer) tabs.push({ id: "developer", label: developer.label(), icon: "send" });
|
|
8549
9446
|
const sectionProps = {
|
|
8550
9447
|
controller,
|
|
8551
9448
|
settings: state.settings,
|
|
8552
9449
|
capabilities: state.capabilities,
|
|
9450
|
+
hostPlatform: state.hostPlatform,
|
|
8553
9451
|
speaking: state.speaking,
|
|
8554
9452
|
invoke,
|
|
8555
9453
|
updateSettings: (next) => invoke("updateSettings", next)
|
|
8556
9454
|
};
|
|
8557
|
-
return /* @__PURE__ */
|
|
8558
|
-
|
|
8559
|
-
{
|
|
8560
|
-
label: settingsLanguage.title(),
|
|
8561
|
-
tabs,
|
|
8562
|
-
active: selectedTab,
|
|
8563
|
-
idPrefix: tabsId,
|
|
8564
|
-
onChange: setActiveTab
|
|
8565
|
-
}
|
|
8566
|
-
), tabs.map((tab) => /* @__PURE__ */ import_react54.default.createElement(
|
|
8567
|
-
"div",
|
|
9455
|
+
return /* @__PURE__ */ import_react58.default.createElement(
|
|
9456
|
+
"section",
|
|
8568
9457
|
{
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
role: "tabpanel",
|
|
8573
|
-
"aria-labelledby": `${tabsId}-tab-${tab.id}`,
|
|
8574
|
-
hidden: selectedTab !== tab.id
|
|
9458
|
+
ref: container,
|
|
9459
|
+
className: "dlv-settings",
|
|
9460
|
+
"aria-label": settingsLanguage.title()
|
|
8575
9461
|
},
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
controller.clearError();
|
|
9462
|
+
/* @__PURE__ */ import_react58.default.createElement(SettingsHeader, { onClose, pluginUpdate }),
|
|
9463
|
+
/* @__PURE__ */ import_react58.default.createElement(
|
|
9464
|
+
SettingsTabs,
|
|
9465
|
+
{
|
|
9466
|
+
label: settingsLanguage.title(),
|
|
9467
|
+
tabs,
|
|
9468
|
+
active: selectedTab,
|
|
9469
|
+
idPrefix: tabsId,
|
|
9470
|
+
onChange: setActiveTab
|
|
8586
9471
|
}
|
|
8587
|
-
|
|
8588
|
-
|
|
9472
|
+
),
|
|
9473
|
+
/* @__PURE__ */ import_react58.default.createElement("div", { className: "dlv-settings-scroll" }, tabs.map((tab) => /* @__PURE__ */ import_react58.default.createElement(
|
|
9474
|
+
"div",
|
|
9475
|
+
{
|
|
9476
|
+
key: tab.id,
|
|
9477
|
+
id: `${tabsId}-panel-${tab.id}`,
|
|
9478
|
+
className: "dlv-settings-panel",
|
|
9479
|
+
role: "tabpanel",
|
|
9480
|
+
"aria-labelledby": `${tabsId}-tab-${tab.id}`,
|
|
9481
|
+
hidden: selectedTab !== tab.id
|
|
9482
|
+
},
|
|
9483
|
+
tab.id === "speech" ? /* @__PURE__ */ import_react58.default.createElement(SpeakSettingsSection, { ...sectionProps }) : tab.id === "recognition" ? /* @__PURE__ */ import_react58.default.createElement(RecognitionSettingsSection, { ...sectionProps }) : /* @__PURE__ */ import_react58.default.createElement(ConversationSettingsSection, { ...sectionProps })
|
|
9484
|
+
))),
|
|
9485
|
+
Developer && /* @__PURE__ */ import_react58.default.createElement("footer", { className: "dlv-settings-footer" }, /* @__PURE__ */ import_react58.default.createElement(Developer, null)),
|
|
9486
|
+
/* @__PURE__ */ import_react58.default.createElement(
|
|
9487
|
+
ErrorMessage,
|
|
9488
|
+
{
|
|
9489
|
+
error: error || state.error,
|
|
9490
|
+
dismissLabel: commons.dismissError(),
|
|
9491
|
+
dismissText: commons.dismiss(),
|
|
9492
|
+
onDismiss: () => {
|
|
9493
|
+
clearError();
|
|
9494
|
+
controller.clearError();
|
|
9495
|
+
}
|
|
9496
|
+
}
|
|
9497
|
+
)
|
|
9498
|
+
);
|
|
8589
9499
|
}
|
|
8590
9500
|
|
|
8591
9501
|
// src/modules/settings/components/createLiveVoiceSettings.tsx
|
|
@@ -8595,7 +9505,7 @@ function createLiveVoiceSettings(..._legacyArguments) {
|
|
|
8595
9505
|
onClose,
|
|
8596
9506
|
pluginUpdate
|
|
8597
9507
|
}) {
|
|
8598
|
-
return /* @__PURE__ */
|
|
9508
|
+
return /* @__PURE__ */ import_react59.default.createElement(LiveVoiceSettings, { controller, onClose, pluginUpdate });
|
|
8599
9509
|
};
|
|
8600
9510
|
}
|
|
8601
9511
|
|
|
@@ -8603,6 +9513,7 @@ function createLiveVoiceSettings(..._legacyArguments) {
|
|
|
8603
9513
|
var SETTINGS_PATH = "/api/dsh-live-voice/settings";
|
|
8604
9514
|
function createSettingsClient(fetchImpl = globalThis.fetch) {
|
|
8605
9515
|
let settings = normalizeSettings({});
|
|
9516
|
+
let hostPlatform;
|
|
8606
9517
|
let queue = Promise.resolve();
|
|
8607
9518
|
const pendingPatches = [];
|
|
8608
9519
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -8615,6 +9526,7 @@ function createSettingsClient(fetchImpl = globalThis.fetch) {
|
|
|
8615
9526
|
});
|
|
8616
9527
|
const body = await response.json();
|
|
8617
9528
|
if (!response.ok || body?.ok !== true) throw new Error("settings-request-failed");
|
|
9529
|
+
hostPlatform = typeof body.hostPlatform === "string" ? body.hostPlatform : void 0;
|
|
8618
9530
|
if (method === "PUT") pendingPatches.shift();
|
|
8619
9531
|
settings = normalizeSettings(Object.assign({}, body.value, ...pendingPatches));
|
|
8620
9532
|
for (const listener of listeners) listener(settings);
|
|
@@ -8626,6 +9538,7 @@ function createSettingsClient(fetchImpl = globalThis.fetch) {
|
|
|
8626
9538
|
return {
|
|
8627
9539
|
ready,
|
|
8628
9540
|
getSnapshot: () => settings,
|
|
9541
|
+
getHostPlatform: () => hostPlatform,
|
|
8629
9542
|
subscribe(listener) {
|
|
8630
9543
|
listeners.add(listener);
|
|
8631
9544
|
return () => {
|
|
@@ -8655,13 +9568,13 @@ function createSettingsClient(fetchImpl = globalThis.fetch) {
|
|
|
8655
9568
|
}
|
|
8656
9569
|
|
|
8657
9570
|
// src/modules/conversation/components/ConversationControls.tsx
|
|
8658
|
-
var
|
|
9571
|
+
var import_react62 = __toESM(require("react"), 1);
|
|
8659
9572
|
|
|
8660
9573
|
// src/modules/conversation/components/MicrophoneButton.tsx
|
|
8661
|
-
var
|
|
9574
|
+
var import_react60 = __toESM(require("react"), 1);
|
|
8662
9575
|
function MicrophoneButton(props) {
|
|
8663
9576
|
const active = Boolean(props["aria-pressed"]);
|
|
8664
|
-
return /* @__PURE__ */
|
|
9577
|
+
return /* @__PURE__ */ import_react60.default.createElement(
|
|
8665
9578
|
IconButton,
|
|
8666
9579
|
{
|
|
8667
9580
|
...props,
|
|
@@ -8673,7 +9586,7 @@ function MicrophoneButton(props) {
|
|
|
8673
9586
|
}
|
|
8674
9587
|
|
|
8675
9588
|
// src/modules/conversation/components/AutoPlaybackToggle.tsx
|
|
8676
|
-
var
|
|
9589
|
+
var import_react61 = __toESM(require("react"), 1);
|
|
8677
9590
|
function AutoPlaybackToggle({ state, invoke, error }) {
|
|
8678
9591
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
8679
9592
|
const { scoped: speak } = useLanguage((ctx) => ctx.speak);
|
|
@@ -8685,7 +9598,7 @@ function AutoPlaybackToggle({ state, invoke, error }) {
|
|
|
8685
9598
|
}) : speak.autoPlayback.status({
|
|
8686
9599
|
state: active ? commons.on() : commons.off()
|
|
8687
9600
|
});
|
|
8688
|
-
return /* @__PURE__ */
|
|
9601
|
+
return /* @__PURE__ */ import_react61.default.createElement(
|
|
8689
9602
|
IconButton,
|
|
8690
9603
|
{
|
|
8691
9604
|
className: "dlv-composer-toggle",
|
|
@@ -8704,27 +9617,20 @@ function AutoPlaybackToggle({ state, invoke, error }) {
|
|
|
8704
9617
|
// src/modules/conversation/components/ConversationControls.tsx
|
|
8705
9618
|
function ConversationControls({ controller }) {
|
|
8706
9619
|
const { scoped: commons } = useLanguage((ctx) => ctx.commons);
|
|
8707
|
-
const { scoped: recognition } = useLanguage((ctx) => ctx.recognition);
|
|
8708
9620
|
const state = useConversationController(controller);
|
|
8709
9621
|
const { invoke, error, clearError } = useConversationActions(controller);
|
|
8710
9622
|
const busy = state.conversation || state.listening || state.starting || state.recognizing;
|
|
8711
|
-
const
|
|
8712
|
-
|
|
8713
|
-
const pending = !capability || !capture;
|
|
8714
|
-
const unavailable = capability?.supported === false || capture?.supported === false;
|
|
8715
|
-
const reason = capture?.supported === false ? capture.reason : capability?.reason;
|
|
8716
|
-
const label = busy ? commons.conversation.end() : pending ? recognition.microphone.checking() : unavailable ? reason || recognition.status.unavailable() : commons.conversation.start();
|
|
8717
|
-
return /* @__PURE__ */ import_react58.default.createElement(import_react58.default.Fragment, null, /* @__PURE__ */ import_react58.default.createElement(AutoPlaybackToggle, { state, invoke, error }), /* @__PURE__ */ import_react58.default.createElement(
|
|
9623
|
+
const label = busy ? commons.conversation.end() : commons.conversation.start();
|
|
9624
|
+
return /* @__PURE__ */ import_react62.default.createElement(import_react62.default.Fragment, null, /* @__PURE__ */ import_react62.default.createElement(AutoPlaybackToggle, { state, invoke, error }), /* @__PURE__ */ import_react62.default.createElement(
|
|
8718
9625
|
MicrophoneButton,
|
|
8719
9626
|
{
|
|
8720
9627
|
label,
|
|
8721
|
-
disabled: !busy && pending,
|
|
8722
9628
|
"aria-pressed": Boolean(busy),
|
|
8723
9629
|
onClick: () => invoke(
|
|
8724
|
-
busy ? state.conversation ? "stopConversationInput" : "cancelDictation" :
|
|
9630
|
+
busy ? state.conversation ? "stopConversationInput" : "cancelDictation" : "startConversation"
|
|
8725
9631
|
)
|
|
8726
9632
|
}
|
|
8727
|
-
), /* @__PURE__ */
|
|
9633
|
+
), /* @__PURE__ */ import_react62.default.createElement(
|
|
8728
9634
|
ErrorMessage,
|
|
8729
9635
|
{
|
|
8730
9636
|
error,
|
|
@@ -8736,7 +9642,7 @@ function ConversationControls({ controller }) {
|
|
|
8736
9642
|
}
|
|
8737
9643
|
|
|
8738
9644
|
// src/modules/conversation/components/SpeakButton.tsx
|
|
8739
|
-
var
|
|
9645
|
+
var import_react63 = __toESM(require("react"), 1);
|
|
8740
9646
|
function SpeakButton({
|
|
8741
9647
|
active = false,
|
|
8742
9648
|
disabled = false,
|
|
@@ -8745,7 +9651,7 @@ function SpeakButton({
|
|
|
8745
9651
|
}) {
|
|
8746
9652
|
const { scoped: speak } = useLanguage((ctx) => ctx.speak);
|
|
8747
9653
|
const resolvedLabel = label ?? (active ? speak.playback.stop() : speak.playback.message());
|
|
8748
|
-
return /* @__PURE__ */
|
|
9654
|
+
return /* @__PURE__ */ import_react63.default.createElement(
|
|
8749
9655
|
IconButton,
|
|
8750
9656
|
{
|
|
8751
9657
|
className: "dlv-speaker",
|
|
@@ -8894,7 +9800,7 @@ var styles = `
|
|
|
8894
9800
|
.dlv-wave{display:block;flex:1 1 180px;min-width:30px;width:0;height:40px;color:var(--dsw-alias-label-primary)}
|
|
8895
9801
|
.dlv-status{flex:1 1 120px;min-width:0;font-size:13px;line-height:1.4;color:var(--dsw-alias-label-secondary)}
|
|
8896
9802
|
.dlv-error{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:13px;max-width:720px;margin:8px auto}
|
|
8897
|
-
.dlv-settings{box-sizing:border-box;padding:
|
|
9803
|
+
.dlv-settings{box-sizing:border-box;padding:8px 2px 20px;width:100%;display:flex;flex-direction:column;gap:20px;min-width:0;max-width:820px;min-height:100%;color:var(--dsw-alias-label-primary);container-type:inline-size}
|
|
8898
9804
|
.dlv-settings h3,.dlv-settings p{margin:0}
|
|
8899
9805
|
.dlv-settings-heading{display:flex;align-items:center;gap:8px;min-width:0;flex-wrap:wrap}
|
|
8900
9806
|
.dlv-plugin-update{display:inline-flex;flex-wrap:wrap;gap:6px;max-width:100%}.dlv-plugin-update-panel{display:flex;flex-wrap:wrap;align-items:center;gap:8px;width:100%;padding:10px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;font-size:12px;overflow-wrap:anywhere}.dlv-plugin-update button{cursor:pointer;font:inherit}.dlv-plugin-update button:disabled{opacity:.6;cursor:default}.dlv-plugin-update button:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:3px}.dlv-settings-heading h3{white-space:nowrap}.dlv-heading-divider{height:1px;min-width:12px;flex:1;background:var(--dsw-alias-border-l1)}.dlv-settings-heading .dlv-star-badge{flex:none}
|
|
@@ -8906,6 +9812,46 @@ var styles = `
|
|
|
8906
9812
|
.dlv-preset-group{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.dlv-settings label.dlv-preset{display:flex;align-items:flex-start;gap:8px;padding:10px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;cursor:pointer}.dlv-settings label.dlv-preset:has(input:checked){border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.dlv-settings label.dlv-preset input{width:auto;margin-top:3px}.dlv-preset span{display:grid;gap:3px}.dlv-vad-summary{font-weight:500}
|
|
8907
9813
|
.dlv-settings-actions{display:flex;flex-wrap:wrap;gap:8px}.dlv-settings-actions button{padding:8px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:inherit;cursor:pointer}.dlv-settings-actions button:disabled{opacity:.45;cursor:default}
|
|
8908
9814
|
@media(max-width:480px){.dlv-settings-heading{gap:6px}.dlv-heading-divider{min-width:4px}.dlv-settings-heading .dlv-star-badge{padding:3px 6px;font-size:10px}.dlv-preset-group{grid-template-columns:1fr}.dlv-pill{flex-wrap:wrap}.dlv-wave{flex-basis:90px}.dlv-status{flex-basis:100px}}
|
|
9815
|
+
|
|
9816
|
+
.dlv-phrase-field{display:grid;gap:7px}.dlv-phrase-box{display:flex;flex-wrap:wrap;gap:6px;padding:9px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;min-width:0}.dlv-phrase-box:focus-within{outline:2px solid var(--dsw-alias-label-primary);outline-offset:2px}.dlv-phrase{display:inline-flex;align-items:center;gap:5px;max-width:100%;padding:3px 7px 3px 10px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:14px;font-size:12px}.dlv-phrase>span{overflow-wrap:anywhere;min-width:0}.dlv-phrase button{border:0;background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:17px;padding:0 3px}.dlv-phrase-box input{border:0!important;outline:0!important;width:120px!important;flex:1;min-width:100px!important;padding:4px!important;background:transparent!important}.dlv-phrase-box[aria-disabled=true]{opacity:.5}
|
|
9817
|
+
.dlv-form-field{display:grid;gap:7px;min-width:0}.dlv-field-label{display:flex;align-items:center;gap:7px;min-width:0}.dlv-hint{display:inline-flex;flex:none}.dlv-hint-trigger{display:inline-flex;align-items:center;justify-content:center;width:17px;height:17px;padding:0;border:1px solid var(--dsw-alias-border-l2);border-radius:50%;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:11px;cursor:help}.dlv-hint-trigger:hover,.dlv-hint-trigger:focus-visible{color:var(--dsw-alias-label-primary);border-color:currentColor}.dlv-hint-bubble{position:fixed;inset:auto;margin:0;z-index:2147483647;box-sizing:border-box;width:300px;max-width:calc(100vw - 24px);max-height:calc(100vh - 24px);overflow:auto;padding:13px 15px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-family:inherit;font-size:12px;font-weight:400;line-height:1.65;box-shadow:0 8px 30px #0004;text-align:left}.dlv-hint-bubble[hidden]{display:none}
|
|
9818
|
+
.dlv-settings{min-height:0!important;overflow:hidden;gap:16px!important;padding-bottom:0!important}.dlv-settings-heading,.dlv-settings-tabs{flex-shrink:0}.dlv-settings-scroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:2px 4px 12px 0;scrollbar-gutter:stable}.dlv-settings-footer{flex:none!important;margin-top:0!important;padding:8px 0 0!important}.dlv-settings-footer .dlv-settings-subcard-body{max-height:240px;overflow-y:auto}.dlv-settings>.dlv-error{flex:none}
|
|
9819
|
+
.dlv-field-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;align-items:start}.dlv-field-pair label{min-width:0}@container(max-width:360px){.dlv-field-pair{grid-template-columns:1fr}}
|
|
9820
|
+
.dlv-diagnostics-launcher{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dlv-diagnostics-button{display:inline-flex;align-items:center;gap:7px;border:0;border-radius:6px;background:transparent;color:var(--dsw-alias-label-secondary);padding:6px 2px;font:inherit;font-size:12px;cursor:pointer}.dlv-diagnostics-button:hover{color:var(--dsw-alias-label-primary)}.dlv-diagnostics-button svg{width:15px;height:15px}.dlv-diagnostics-launcher [role=alert]{flex-basis:100%;margin:0}
|
|
9821
|
+
@container(max-width:250px){.dlv-settings-tabs{flex-direction:column}.dlv-settings-tab{flex:0 1 auto;white-space:normal;overflow-wrap:anywhere;padding:8px 4px}.dlv-section-content{padding-inline-start:12px}.dlv-version-badges{flex-wrap:wrap}.dlv-settings-heading{overflow-wrap:anywhere}.dlv-settings-heading .dlv-heading-divider{display:none}.dlv-settings-heading .dlv-star-badge{white-space:normal}.dlv-preset-group{grid-template-columns:1fr}.dlv-settings-actions button{max-width:100%;white-space:normal}}
|
|
9822
|
+
/* Primary sections stay visible; secondary settings use quieter disclosures. */
|
|
9823
|
+
.dlv-settings-tabs{display:flex;flex-wrap:wrap;align-items:stretch;gap:4px;padding:4px;overflow:visible;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-bg-layer-2)}
|
|
9824
|
+
.dlv-settings-tab{flex:1 0 auto;justify-content:center;min-width:0;padding:10px 14px;font-size:13px;line-height:18px;border-radius:8px;white-space:nowrap;text-align:center}
|
|
9825
|
+
.dlv-settings-tab[data-active=true]{background:var(--dsw-alias-bg-layer-1);box-shadow:0 1px 4px #0001}
|
|
9826
|
+
.dlv-settings-tab[data-active=true]:after,.dlv-settings-tab:focus-visible:after{display:none}
|
|
9827
|
+
.dlv-settings-card-body{gap:22px;padding:0}
|
|
9828
|
+
.dlv-settings-section{min-width:0;display:grid;gap:14px;padding:0 0 22px;border-bottom:1px solid var(--dsw-alias-border-l1)}
|
|
9829
|
+
.dlv-settings-section:last-child{border-bottom:0;padding-bottom:0}
|
|
9830
|
+
.dlv-section-heading h4{display:flex;align-items:center;gap:9px;margin:0;font-size:14px;line-height:22px;font-weight:650}
|
|
9831
|
+
.dlv-section-heading svg{width:18px;height:18px;color:var(--dsw-alias-label-secondary);flex:none}
|
|
9832
|
+
.dlv-section-content{display:grid;gap:14px;min-width:0;padding-inline-start:27px}
|
|
9833
|
+
.dlv-settings :is(input,select,textarea){min-width:0;font-size:13px;padding:10px 12px}
|
|
9834
|
+
.dlv-settings label{font-size:13px;font-weight:500;gap:7px;min-width:0}
|
|
9835
|
+
.dlv-settings label.dlv-check{align-items:center;line-height:1.5}
|
|
9836
|
+
.dlv-settings label.dlv-check input{flex:none;width:16px;height:16px;padding:0;margin:0;accent-color:var(--dsw-alias-label-primary)}
|
|
9837
|
+
.dlv-settings .dlv-setting-description{margin:-5px 0 0;font-size:12px;line-height:1.6}
|
|
9838
|
+
.dlv-settings .dlv-check + .dlv-setting-description{margin:6px 0 0 24px}
|
|
9839
|
+
.dlv-settings-subcard{margin:0;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;overflow:clip}
|
|
9840
|
+
.dlv-settings-subcard>summary{border:0;background:transparent;padding:12px;font-size:13px;line-height:20px}
|
|
9841
|
+
.dlv-settings-subcard>summary:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
9842
|
+
.dlv-settings-subcard[open]>summary{border-bottom:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary)}
|
|
9843
|
+
.dlv-settings-subcard-body{display:grid;gap:14px;padding:16px!important;min-width:0}
|
|
9844
|
+
.dlv-section-content>.dlv-settings-subcard{background:color-mix(in srgb,var(--dsw-alias-bg-layer-2) 45%,transparent);border-left:3px solid var(--dsw-alias-border-l2)}
|
|
9845
|
+
.dlv-settings-footer{margin-top:auto;padding-top:18px;border-top:1px solid var(--dsw-alias-border-l1)}
|
|
9846
|
+
.dlv-settings-footer>.dlv-settings-subcard{border:0}
|
|
9847
|
+
.dlv-settings-footer summary{padding:8px 0;color:var(--dsw-alias-label-tertiary);font-size:12px}
|
|
9848
|
+
.dlv-settings .dlv-star-badge{background:transparent;border:0;color:var(--dsw-alias-label-tertiary);font-weight:400;font-size:11px;padding:0}
|
|
9849
|
+
.dlv-settings-heading h3{font-size:18px;letter-spacing:-.02em}
|
|
9850
|
+
.dlv-settings :is(button,a,textarea,summary):focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:3px}
|
|
9851
|
+
@container(max-width:360px){.dlv-settings-tabs{display:flex;flex-wrap:wrap}.dlv-settings-tab{flex:1 0 auto;font-size:12px;padding:8px;gap:5px}.dlv-settings-heading h3{flex-basis:100%}.dlv-settings-subcard-body{padding:12px!important}}
|
|
9852
|
+
.dlv-settings-subcard-body>button{justify-self:start;padding:7px 11px;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;background:var(--dsw-alias-bg-layer-1);color:inherit;font:inherit;font-size:12px;cursor:pointer}
|
|
9853
|
+
@container(max-width:250px){.dlv-settings-tabs{flex-direction:column}.dlv-settings-tab{flex:0 1 auto;white-space:normal;overflow-wrap:anywhere;max-width:100%;padding:8px 4px}.dlv-section-content{padding-inline-start:12px}.dlv-settings-heading .dlv-version-badges{flex-wrap:wrap}.dlv-settings-heading .dlv-star-badge{white-space:normal;max-width:100%}}
|
|
9854
|
+
details.dlv-settings-section{display:block}.dlv-settings-section>summary{display:flex;align-items:center;gap:12px;cursor:pointer;list-style:none}.dlv-settings-section>summary::-webkit-details-marker{display:none}.dlv-settings-section>summary h4{flex:1;min-width:0}.dlv-settings-section>summary>.dlv-section-chevron{width:16px;height:16px;flex:none;transition:transform .18s ease;color:var(--dsw-alias-label-secondary)}.dlv-settings-section[open]>summary>.dlv-section-chevron{transform:rotate(180deg)}.dlv-settings-section>summary+.dlv-section-content{margin-top:14px}details.dlv-settings-section:not([open])>.dlv-section-content{display:none}@media(prefers-reduced-motion:reduce){.dlv-settings-section>summary>.dlv-section-chevron{transition:none}}
|
|
8909
9855
|
`;
|
|
8910
9856
|
|
|
8911
9857
|
// src/modules/settings/services/pluginUpdate.ts
|
|
@@ -9137,8 +10083,11 @@ function apply(ctx) {
|
|
|
9137
10083
|
const t = registerLiveVoiceLocales(ctx);
|
|
9138
10084
|
const SettingsPanel = createLiveVoiceSettings(t, ctx.locale);
|
|
9139
10085
|
const controllers = /* @__PURE__ */ new Map();
|
|
10086
|
+
const speechMemory = new SessionSpeechMemory();
|
|
10087
|
+
let automaticSpeechEnabled;
|
|
9140
10088
|
const retiring = /* @__PURE__ */ new Set();
|
|
9141
10089
|
const preferences = createSettingsClient();
|
|
10090
|
+
let preferencesLoaded = false;
|
|
9142
10091
|
const settingsControllers = /* @__PURE__ */ new Set();
|
|
9143
10092
|
let disposed = false;
|
|
9144
10093
|
let voiceModeActive = false;
|
|
@@ -9169,24 +10118,30 @@ function apply(ctx) {
|
|
|
9169
10118
|
canAutoSend: () => !!meetingEntry && !meetingEntry.controller.getSnapshot().recognizing && !meetingEntry.controller.getSnapshot().pendingTranscriptions
|
|
9170
10119
|
},
|
|
9171
10120
|
settings: () => preferences.getSnapshot(),
|
|
10121
|
+
savePreferences: (controller, next) => savePreferences(controller, next),
|
|
9172
10122
|
translate: (key) => t("dsh-live-voice.meeting." + key),
|
|
9173
10123
|
createSource: (source, settings) => {
|
|
9174
10124
|
const meter = source === "shared" ? new SharedAudioMeter() : new MicrophoneMeter();
|
|
9175
|
-
return { meter, engine: recognitionFor(settings, meter) };
|
|
10125
|
+
return { meter, engine: recognitionFor(settings, meter, source) };
|
|
9176
10126
|
}
|
|
9177
10127
|
});
|
|
9178
10128
|
let updateManager;
|
|
9179
|
-
if (typeof ctx.inject === "function")
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
10129
|
+
if (typeof ctx.inject === "function")
|
|
10130
|
+
ctx.inject(["remote", "remote.pluginManager"], (remoteCtx) => {
|
|
10131
|
+
updateManager = remoteCtx.remote.pluginManager;
|
|
10132
|
+
remoteCtx.effect(
|
|
10133
|
+
() => () => {
|
|
10134
|
+
updateManager = void 0;
|
|
10135
|
+
},
|
|
10136
|
+
"dsh-live-voice: release update manager"
|
|
10137
|
+
);
|
|
10138
|
+
});
|
|
9185
10139
|
const pluginUpdate = createPluginUpdate({
|
|
9186
10140
|
manager: () => updateManager,
|
|
9187
10141
|
isBusy: () => {
|
|
9188
10142
|
const m = meeting.getSnapshot();
|
|
9189
|
-
if (disposed || voiceModeActive || retiring.size || m.active || m.shared.starting || m.shared.pending || m.microphone.starting || m.microphone.pending)
|
|
10143
|
+
if (disposed || voiceModeActive || retiring.size || m.active || m.shared.starting || m.shared.pending || m.microphone.starting || m.microphone.pending)
|
|
10144
|
+
return true;
|
|
9190
10145
|
return [...controllers.values()].some((entry) => {
|
|
9191
10146
|
const s = entry.controller.getSnapshot();
|
|
9192
10147
|
return s.starting || s.listening || s.recognizing || s.pendingTranscriptions || s.speaking || s.autoSendPending || s.speechBarVisible;
|
|
@@ -9286,7 +10241,7 @@ function apply(ctx) {
|
|
|
9286
10241
|
"recognitionMaxUtteranceSeconds"
|
|
9287
10242
|
]);
|
|
9288
10243
|
const changesRecognition = (next) => Object.keys(next).some((key) => recognitionSettingKeys.has(key));
|
|
9289
|
-
const recognitionFor = (settings, meter) => settings.recognitionEngine === "qwen-http" ? new QwenHttpRecognitionEngine({
|
|
10244
|
+
const recognitionFor = (settings, meter, inputSource = "microphone") => settings.recognitionEngine === "qwen-http" ? new QwenHttpRecognitionEngine({
|
|
9290
10245
|
meter,
|
|
9291
10246
|
vadErrorMessage: (error) => t(
|
|
9292
10247
|
"dsh-live-voice.recognition.silero.error." + (error?.code === "overloaded" ? "overloaded" : "failed")
|
|
@@ -9305,6 +10260,7 @@ function apply(ctx) {
|
|
|
9305
10260
|
voiceDetectionCustomSilenceMs: settings.voiceDetectionCustomSilenceMs,
|
|
9306
10261
|
maxUtteranceSeconds: settings.recognitionMaxUtteranceSeconds
|
|
9307
10262
|
}) : new BrowserRecognitionEngine({
|
|
10263
|
+
...inputSource === "shared" ? { meter, inputSource } : {},
|
|
9308
10264
|
processLocally: settings.recognitionProcessLocally,
|
|
9309
10265
|
autoInstallLocalPack: settings.recognitionAutoInstall
|
|
9310
10266
|
});
|
|
@@ -9323,10 +10279,18 @@ function apply(ctx) {
|
|
|
9323
10279
|
}
|
|
9324
10280
|
const unsubscribePreferences = preferences.subscribe((settings) => {
|
|
9325
10281
|
if (disposed) return;
|
|
10282
|
+
preferencesLoaded = true;
|
|
10283
|
+
const speechChanged = automaticSpeechEnabled !== void 0 && automaticSpeechEnabled !== settings.announceAssistantMessages;
|
|
10284
|
+
automaticSpeechEnabled = settings.announceAssistantMessages;
|
|
10285
|
+
if (speechChanged) speechMemory.reset();
|
|
9326
10286
|
meeting.applySettings(settings);
|
|
9327
10287
|
for (const entry of controllers.values()) {
|
|
9328
10288
|
if (entry.closed) continue;
|
|
9329
10289
|
entry.applySettings(settings);
|
|
10290
|
+
if (speechChanged) {
|
|
10291
|
+
entry.speechState = speechMemory.session(entry.key);
|
|
10292
|
+
entry.refreshSpeech(true);
|
|
10293
|
+
} else if (entry.speechAttached) entry.refreshSpeech();
|
|
9330
10294
|
}
|
|
9331
10295
|
for (const c of settingsControllers) {
|
|
9332
10296
|
if (c.disposed) continue;
|
|
@@ -9334,16 +10298,51 @@ function apply(ctx) {
|
|
|
9334
10298
|
if ([...recognitionSettingKeys].some((key) => previous[key] !== settings[key]))
|
|
9335
10299
|
c.replaceRecognition(recognitionFor(settings, c.meter));
|
|
9336
10300
|
c.applySavedSettings(settings);
|
|
10301
|
+
c.patch({ hostPlatform: preferences.getHostPlatform() });
|
|
9337
10302
|
for (const engine of Object.values(c.engines)) engine.lang = settings.lang;
|
|
9338
|
-
run(c, c.refreshCapabilities());
|
|
10303
|
+
run(c, c.refreshCapabilities({ localOnly: true }));
|
|
9339
10304
|
}
|
|
9340
10305
|
});
|
|
9341
10306
|
ctx.effect(
|
|
9342
10307
|
() => () => unsubscribePreferences(),
|
|
9343
10308
|
"dsh-live-voice: remove preferences subscription"
|
|
9344
10309
|
);
|
|
10310
|
+
function suspendSessionSpeech(entry) {
|
|
10311
|
+
if (!entry.speechAttached) return;
|
|
10312
|
+
if (!entry.controller.speechSuspended || !entry.speechState.checkpoint)
|
|
10313
|
+
entry.speechState.checkpoint = entry.controller.checkpointSpeech();
|
|
10314
|
+
entry.speechAttached = false;
|
|
10315
|
+
++entry.speechRequest;
|
|
10316
|
+
const stopped = entry.controller.suspendSpeech();
|
|
10317
|
+
entry.speechRelease = Promise.resolve(stopped).then(() => {
|
|
10318
|
+
if (entry.controller.speechStopError) throw entry.controller.speechStopError;
|
|
10319
|
+
if (entry.controller.inputReleaseError) throw entry.controller.inputReleaseError;
|
|
10320
|
+
});
|
|
10321
|
+
entry.speechRelease.catch(() => {
|
|
10322
|
+
});
|
|
10323
|
+
}
|
|
10324
|
+
function activateSessionSpeech(entry) {
|
|
10325
|
+
const request = ++entry.speechRequest;
|
|
10326
|
+
const releases = [
|
|
10327
|
+
...retiring,
|
|
10328
|
+
...settingsControllers,
|
|
10329
|
+
...[...controllers.values()].filter((other) => other !== entry).map((other) => ({ endConversation: () => other.speechRelease }))
|
|
10330
|
+
];
|
|
10331
|
+
return ownership.run(entry.controller, releases, async () => {
|
|
10332
|
+
await preferences.ready;
|
|
10333
|
+
await entry.speechRelease;
|
|
10334
|
+
if (disposed || entry.closed || !entry.speechAttached || request !== entry.speechRequest)
|
|
10335
|
+
return;
|
|
10336
|
+
entry.controller.restoreSpeech(entry.speechState.checkpoint);
|
|
10337
|
+
entry.speechState.checkpoint = null;
|
|
10338
|
+
entry.refreshSpeech(!entry.speechState.attached);
|
|
10339
|
+
entry.speechState.attached = true;
|
|
10340
|
+
entry.controller.activateSpeech();
|
|
10341
|
+
});
|
|
10342
|
+
}
|
|
9345
10343
|
function retire(entry) {
|
|
9346
10344
|
if (entry.closed) return;
|
|
10345
|
+
suspendSessionSpeech(entry);
|
|
9347
10346
|
entry.closed = true;
|
|
9348
10347
|
if (meetingEntry === entry) {
|
|
9349
10348
|
meeting.cancelDelivery();
|
|
@@ -9366,15 +10365,27 @@ function apply(ctx) {
|
|
|
9366
10365
|
if (controllers.get(entry.key) === entry) controllers.delete(entry.key);
|
|
9367
10366
|
notifyDiagnostics();
|
|
9368
10367
|
const done = run(entry.controller, entry.controller.dispose());
|
|
9369
|
-
const barrier = {
|
|
10368
|
+
const barrier = {
|
|
10369
|
+
endConversation: async () => {
|
|
10370
|
+
await done;
|
|
10371
|
+
if (entry.controller.speechStopError) throw entry.controller.speechStopError;
|
|
10372
|
+
if (entry.controller.inputReleaseError) throw entry.controller.inputReleaseError;
|
|
10373
|
+
}
|
|
10374
|
+
};
|
|
9370
10375
|
retiring.add(barrier);
|
|
9371
|
-
void done.finally(() =>
|
|
10376
|
+
void done.finally(() => {
|
|
10377
|
+
if (!entry.controller.speechStopError && !entry.controller.inputReleaseError)
|
|
10378
|
+
retiring.delete(barrier);
|
|
10379
|
+
});
|
|
9372
10380
|
}
|
|
9373
10381
|
function get(sessionId) {
|
|
9374
10382
|
const key = String(sessionId);
|
|
9375
10383
|
if (controllers.has(key)) return controllers.get(key);
|
|
9376
10384
|
const entry = {
|
|
9377
10385
|
key,
|
|
10386
|
+
speechState: speechMemory.session(key),
|
|
10387
|
+
speechAttached: false,
|
|
10388
|
+
speechRequest: 0,
|
|
9378
10389
|
draft: "",
|
|
9379
10390
|
pendingDraft: void 0,
|
|
9380
10391
|
publishedDraft: void 0,
|
|
@@ -9474,6 +10485,8 @@ function apply(ctx) {
|
|
|
9474
10485
|
settings
|
|
9475
10486
|
});
|
|
9476
10487
|
const controller = entry.controller;
|
|
10488
|
+
controller.speechSuspended = true;
|
|
10489
|
+
controller.restoreSpeech(entry.speechState.checkpoint);
|
|
9477
10490
|
entry.unsubscribeVoiceContext = controller.subscribe(() => {
|
|
9478
10491
|
publishVoiceContext(entry);
|
|
9479
10492
|
notifyDiagnostics();
|
|
@@ -9489,28 +10502,33 @@ function apply(ctx) {
|
|
|
9489
10502
|
return () => entry.chatListeners.delete(listener);
|
|
9490
10503
|
};
|
|
9491
10504
|
entry.readChat = entry.chat.getSnapshot.bind(entry.chat);
|
|
9492
|
-
const
|
|
9493
|
-
const observed = /* @__PURE__ */ new Set();
|
|
9494
|
-
let baselined = false;
|
|
9495
|
-
const refresh = (forceBaseline = false) => {
|
|
10505
|
+
const refresh = (reset = false) => {
|
|
9496
10506
|
if (disposed || entry.closed) return;
|
|
9497
10507
|
const snapshot = entry.readChat();
|
|
9498
|
-
const
|
|
9499
|
-
|
|
10508
|
+
const messages = assistantMessages(snapshot);
|
|
10509
|
+
const memory = entry.speechState;
|
|
10510
|
+
if (!preferencesLoaded && memory.attached) return;
|
|
10511
|
+
const initial = !memory.baselined;
|
|
9500
10512
|
const userSeq = latestUserSequence(snapshot);
|
|
9501
|
-
if (!
|
|
10513
|
+
if (!initial && entry.speechAttached && userSeq > entry.userSeq && controller.getSnapshot().settings.interruptSpeechOnUserMessage && (controller.getSnapshot().speaking || controller.getSnapshot().paused))
|
|
9502
10514
|
run(controller, controller.stopSpeech());
|
|
9503
10515
|
entry.userSeq = Math.max(entry.userSeq ?? -1, userSeq);
|
|
9504
|
-
|
|
9505
|
-
|
|
10516
|
+
if (!entry.speechAttached && memory.baselined && !reset) return;
|
|
10517
|
+
for (const message2 of messages) {
|
|
10518
|
+
const previousText = memory.textById.get(message2.id);
|
|
10519
|
+
const rewritten = !reset && memory.attached && previousText !== void 0 && !message2.text.startsWith(previousText);
|
|
10520
|
+
if (message2.interrupted || rewritten) controller.discardSpeechMessage(message2.id);
|
|
10521
|
+
memory.textById.set(message2.id, message2.text);
|
|
10522
|
+
const baseline = speechMemory.baseline(memory, message2, initial);
|
|
9506
10523
|
controller.observeMessage(message2.id, message2.text, {
|
|
9507
10524
|
complete: message2.complete,
|
|
9508
|
-
baseline:
|
|
10525
|
+
baseline: !preferencesLoaded || reset || baseline || message2.interrupted
|
|
9509
10526
|
});
|
|
9510
|
-
observed.add(message2.id);
|
|
9511
10527
|
}
|
|
10528
|
+
if (messages.length) memory.baselined = true;
|
|
9512
10529
|
};
|
|
9513
|
-
refresh
|
|
10530
|
+
entry.refreshSpeech = refresh;
|
|
10531
|
+
refresh();
|
|
9514
10532
|
entry.unsubscribe = entry.chat.subscribe(() => {
|
|
9515
10533
|
refresh();
|
|
9516
10534
|
for (const listener of entry.chatListeners) listener();
|
|
@@ -9570,7 +10588,7 @@ function apply(ctx) {
|
|
|
9570
10588
|
publishVoiceContext(entry);
|
|
9571
10589
|
engineBrowser.lang = controller.getSnapshot().settings.lang;
|
|
9572
10590
|
engineQwen.lang = controller.getSnapshot().settings.lang;
|
|
9573
|
-
run(controller, controller.refreshCapabilities());
|
|
10591
|
+
run(controller, controller.refreshCapabilities({ localOnly: true }));
|
|
9574
10592
|
};
|
|
9575
10593
|
controller.updateSettings = (next) => {
|
|
9576
10594
|
if (disposed || entry.closed) return;
|
|
@@ -9586,6 +10604,27 @@ function apply(ctx) {
|
|
|
9586
10604
|
]) {
|
|
9587
10605
|
const original = controller[method].bind(controller);
|
|
9588
10606
|
controller[method] = (...args) => {
|
|
10607
|
+
if (method === "endConversation" && args[0] === true && !entry.speechAttached) {
|
|
10608
|
+
controller.patch({ conversation: false });
|
|
10609
|
+
return Promise.all([
|
|
10610
|
+
controller.stopListening(),
|
|
10611
|
+
VoiceCoordinator.prototype.stopSpeech.call(controller, false)
|
|
10612
|
+
]);
|
|
10613
|
+
}
|
|
10614
|
+
if (!entry.closed && (method === "stopSpeech" || method === "endConversation")) {
|
|
10615
|
+
const parked = entry.speechState.checkpoint;
|
|
10616
|
+
if (parked) {
|
|
10617
|
+
parked.suppressed = [
|
|
10618
|
+
.../* @__PURE__ */ new Set([
|
|
10619
|
+
...parked.suppressed,
|
|
10620
|
+
...parked.unfinished,
|
|
10621
|
+
...parked.pending.map((item) => item.id)
|
|
10622
|
+
])
|
|
10623
|
+
];
|
|
10624
|
+
parked.pending = [];
|
|
10625
|
+
parked.paused = false;
|
|
10626
|
+
}
|
|
10627
|
+
}
|
|
9589
10628
|
entry.request++;
|
|
9590
10629
|
if (method === "endConversation" && args[0] !== true || method === "stopConversationInput")
|
|
9591
10630
|
voiceModeActive = false;
|
|
@@ -9606,7 +10645,6 @@ function apply(ctx) {
|
|
|
9606
10645
|
if (disposed || entry.closed || !entry.refs) return Promise.resolve();
|
|
9607
10646
|
if (method !== "speak" && !entry.composers.size) return Promise.resolve();
|
|
9608
10647
|
if (method === "startConversation" || method === "takeMicrophone") {
|
|
9609
|
-
refresh(true);
|
|
9610
10648
|
voiceModeActive = true;
|
|
9611
10649
|
}
|
|
9612
10650
|
const request = ++entry.request;
|
|
@@ -9655,12 +10693,12 @@ function apply(ctx) {
|
|
|
9655
10693
|
if (!entry.closed)
|
|
9656
10694
|
controller.patch({ error: t("dsh-live-voice.settings.persistence.loadError") });
|
|
9657
10695
|
});
|
|
9658
|
-
run(controller, controller.refreshCapabilities());
|
|
10696
|
+
run(controller, controller.refreshCapabilities({ localOnly: true }));
|
|
9659
10697
|
return entry;
|
|
9660
10698
|
}
|
|
9661
10699
|
function useEntry(sessionId, kind) {
|
|
9662
|
-
const [entry, setEntry] =
|
|
9663
|
-
|
|
10700
|
+
const [entry, setEntry] = import_react64.default.useState(null);
|
|
10701
|
+
import_react64.default.useLayoutEffect(() => {
|
|
9664
10702
|
if (disposed) return;
|
|
9665
10703
|
const current = get(sessionId);
|
|
9666
10704
|
current.refs++;
|
|
@@ -9680,11 +10718,12 @@ function apply(ctx) {
|
|
|
9680
10718
|
function useComposer(entry, props) {
|
|
9681
10719
|
const subscribedInput = props.useInput?.((value) => value);
|
|
9682
10720
|
const input = subscribedInput ?? props.input;
|
|
9683
|
-
const token =
|
|
9684
|
-
|
|
10721
|
+
const token = import_react64.default.useRef({});
|
|
10722
|
+
import_react64.default.useLayoutEffect(() => {
|
|
9685
10723
|
if (!entry || entry.closed || disposed) return;
|
|
9686
10724
|
return () => {
|
|
9687
10725
|
entry.composers.delete(token.current);
|
|
10726
|
+
if (!entry.composers.size) suspendSessionSpeech(entry);
|
|
9688
10727
|
if (meetingEntry === entry && !entry.composers.size) {
|
|
9689
10728
|
meeting.cancelDelivery();
|
|
9690
10729
|
meetingEntry = null;
|
|
@@ -9692,10 +10731,11 @@ function apply(ctx) {
|
|
|
9692
10731
|
}
|
|
9693
10732
|
};
|
|
9694
10733
|
}, [entry]);
|
|
9695
|
-
|
|
10734
|
+
import_react64.default.useLayoutEffect(() => {
|
|
9696
10735
|
if (!entry || entry.closed || disposed) return;
|
|
9697
10736
|
if (!input || typeof props.inputActions?.setDraft !== "function") return;
|
|
9698
10737
|
if (meetingEntry !== entry) {
|
|
10738
|
+
if (meetingEntry) suspendSessionSpeech(meetingEntry);
|
|
9699
10739
|
meeting.cancelDelivery();
|
|
9700
10740
|
meetingEntry = entry;
|
|
9701
10741
|
entry.controller.setExternalSpeechActivity(sharedSpeechActive);
|
|
@@ -9725,10 +10765,18 @@ function apply(ctx) {
|
|
|
9725
10765
|
);
|
|
9726
10766
|
}
|
|
9727
10767
|
});
|
|
9728
|
-
|
|
9729
|
-
|
|
10768
|
+
const attachSpeech = !entry.speechAttached;
|
|
10769
|
+
if (attachSpeech) entry.speechAttached = true;
|
|
10770
|
+
const inputReady = voiceModeActive && !entry.controller.getSnapshot().conversation ? entry.controller.startConversation() : Promise.resolve();
|
|
10771
|
+
run(
|
|
10772
|
+
entry.controller,
|
|
10773
|
+
Promise.resolve(inputReady).then(() => {
|
|
10774
|
+
if (attachSpeech && entry.speechAttached && !entry.closed)
|
|
10775
|
+
return activateSessionSpeech(entry);
|
|
10776
|
+
})
|
|
10777
|
+
);
|
|
9730
10778
|
}, [entry, input, props.inputActions]);
|
|
9731
|
-
|
|
10779
|
+
import_react64.default.useLayoutEffect(() => {
|
|
9732
10780
|
if (!entry || entry.closed || disposed || !input) return;
|
|
9733
10781
|
const published = typeof input.draft === "string" ? input.draft : "";
|
|
9734
10782
|
entry.publishedDraft = published;
|
|
@@ -9747,7 +10795,7 @@ function apply(ctx) {
|
|
|
9747
10795
|
function Buttons(props) {
|
|
9748
10796
|
const entry = useEntry(props.sessionId, "buttons");
|
|
9749
10797
|
useComposer(entry, props);
|
|
9750
|
-
return entry ? /* @__PURE__ */
|
|
10798
|
+
return entry ? /* @__PURE__ */ import_react64.default.createElement("div", { className: "dlv-composer-toggles" }, /* @__PURE__ */ import_react64.default.createElement(
|
|
9751
10799
|
MeetingToggle,
|
|
9752
10800
|
{
|
|
9753
10801
|
meeting: entry.meeting,
|
|
@@ -9757,11 +10805,11 @@ function apply(ctx) {
|
|
|
9757
10805
|
else entry.startMeetingSource("shared");
|
|
9758
10806
|
}
|
|
9759
10807
|
}
|
|
9760
|
-
), /* @__PURE__ */
|
|
10808
|
+
), /* @__PURE__ */ import_react64.default.createElement(ConversationControls, { controller: entry.controller })) : null;
|
|
9761
10809
|
}
|
|
9762
10810
|
function Settings() {
|
|
9763
|
-
const [controller, setController] =
|
|
9764
|
-
|
|
10811
|
+
const [controller, setController] = import_react64.default.useState(null);
|
|
10812
|
+
import_react64.default.useEffect(() => {
|
|
9765
10813
|
const settings = preferences.getSnapshot();
|
|
9766
10814
|
const browser = new BrowserSpeakingEngine({ lang: settings.lang });
|
|
9767
10815
|
const qwen = new QwenHttpSpeakingEngine({ lang: settings.lang });
|
|
@@ -9815,12 +10863,13 @@ function apply(ctx) {
|
|
|
9815
10863
|
const settings2 = c.getSnapshot().settings;
|
|
9816
10864
|
if (changesRecognition(next)) c.replaceRecognition(recognitionFor(settings2, c.meter));
|
|
9817
10865
|
const saved = savePreferences(c, next);
|
|
9818
|
-
run(c, c.refreshCapabilities());
|
|
10866
|
+
run(c, c.refreshCapabilities({ localOnly: true }));
|
|
9819
10867
|
await saved;
|
|
9820
10868
|
if (revision !== settingsRevision || disposed || c.disposed) return;
|
|
9821
10869
|
};
|
|
9822
|
-
const refresh = () => run(c, c.refreshCapabilities());
|
|
10870
|
+
const refresh = () => run(c, c.refreshCapabilities({ localOnly: true }));
|
|
9823
10871
|
document.addEventListener("dsh-live-voice:capabilitieschanged", refresh);
|
|
10872
|
+
c.patch({ hostPlatform: preferences.getHostPlatform() });
|
|
9824
10873
|
setController(c);
|
|
9825
10874
|
refresh();
|
|
9826
10875
|
return () => {
|
|
@@ -9831,21 +10880,21 @@ function apply(ctx) {
|
|
|
9831
10880
|
void c.dispose();
|
|
9832
10881
|
};
|
|
9833
10882
|
}, []);
|
|
9834
|
-
return controller ? /* @__PURE__ */
|
|
10883
|
+
return controller ? /* @__PURE__ */ import_react64.default.createElement(SettingsPanel, { controller, pluginUpdate }) : null;
|
|
9835
10884
|
}
|
|
9836
10885
|
registerSettingsSlot(ctx, Settings, () => t("dsh-live-voice.commons.pluginName"));
|
|
9837
10886
|
function Dock(props) {
|
|
9838
10887
|
const entry = useEntry(props.sessionId, "dock");
|
|
9839
10888
|
useComposer(entry, props);
|
|
9840
|
-
return entry ? /* @__PURE__ */
|
|
10889
|
+
return entry ? /* @__PURE__ */ import_react64.default.createElement("div", { className: "dlv-bar-stack" }, /* @__PURE__ */ import_react64.default.createElement(SpeechStatusBar, { controller: entry.controller }), /* @__PURE__ */ import_react64.default.createElement(MeetingBars, { meeting: entry.meeting }), /* @__PURE__ */ import_react64.default.createElement(ConversationStatusBar, { controller: entry.controller, includeSpeech: false })) : null;
|
|
9841
10890
|
}
|
|
9842
10891
|
function QuestionStatusView({ entry }) {
|
|
9843
|
-
const snapshot =
|
|
10892
|
+
const snapshot = import_react64.default.useSyncExternalStore(
|
|
9844
10893
|
entry.controller.subscribe,
|
|
9845
10894
|
entry.controller.getSnapshot
|
|
9846
10895
|
);
|
|
9847
|
-
const [overlayStyle, setOverlayStyle] =
|
|
9848
|
-
|
|
10896
|
+
const [overlayStyle, setOverlayStyle] = import_react64.default.useState();
|
|
10897
|
+
import_react64.default.useLayoutEffect(() => {
|
|
9849
10898
|
if (!snapshot.answeringQuestion) return;
|
|
9850
10899
|
const seat = document.querySelector("[data-composer-seat]");
|
|
9851
10900
|
if (!seat) return;
|
|
@@ -9867,7 +10916,7 @@ function apply(ctx) {
|
|
|
9867
10916
|
}, [snapshot.answeringQuestion]);
|
|
9868
10917
|
const target = typeof document === "undefined" ? null : document.body;
|
|
9869
10918
|
return snapshot.answeringQuestion && target && overlayStyle ? (0, import_react_dom.createPortal)(
|
|
9870
|
-
/* @__PURE__ */
|
|
10919
|
+
/* @__PURE__ */ import_react64.default.createElement(
|
|
9871
10920
|
ConversationStatusBar,
|
|
9872
10921
|
{
|
|
9873
10922
|
controller: entry.controller,
|
|
@@ -9881,24 +10930,21 @@ function apply(ctx) {
|
|
|
9881
10930
|
}
|
|
9882
10931
|
function QuestionStatus(props) {
|
|
9883
10932
|
const entry = useEntry(props.sessionId, "question-status");
|
|
9884
|
-
return entry ? /* @__PURE__ */
|
|
10933
|
+
return entry ? /* @__PURE__ */ import_react64.default.createElement(QuestionStatusView, { entry }) : null;
|
|
9885
10934
|
}
|
|
9886
10935
|
function ActionView({ entry, messageId }) {
|
|
9887
|
-
const snapshot =
|
|
10936
|
+
const snapshot = import_react64.default.useSyncExternalStore(
|
|
9888
10937
|
entry.controller.subscribe,
|
|
9889
10938
|
entry.controller.getSnapshot
|
|
9890
10939
|
);
|
|
9891
|
-
const chat =
|
|
10940
|
+
const chat = import_react64.default.useSyncExternalStore(entry.subscribeChat, entry.readChat);
|
|
9892
10941
|
const message2 = addressedTurn(assistantMessages(chat), messageId);
|
|
9893
|
-
const capability = snapshot.capabilities[snapshot.settings.engine];
|
|
9894
10942
|
const active = snapshot.speaking && message2.id === snapshot.activeMessageId;
|
|
9895
|
-
|
|
9896
|
-
return /* @__PURE__ */ import_react60.default.createElement(
|
|
10943
|
+
return /* @__PURE__ */ import_react64.default.createElement(
|
|
9897
10944
|
SpeakButton,
|
|
9898
10945
|
{
|
|
9899
10946
|
active,
|
|
9900
|
-
disabled: !message2.text.trim()
|
|
9901
|
-
label: unavailable ? capability?.reason || t("dsh-live-voice.speak.output.checking") : void 0,
|
|
10947
|
+
disabled: !message2.text.trim(),
|
|
9902
10948
|
onClick: () => run(
|
|
9903
10949
|
entry.controller,
|
|
9904
10950
|
active ? entry.controller.stopSpeech() : entry.controller.speak(message2.text, message2.id)
|
|
@@ -9908,7 +10954,7 @@ function apply(ctx) {
|
|
|
9908
10954
|
}
|
|
9909
10955
|
function Action(props) {
|
|
9910
10956
|
const entry = useEntry(props.sessionId, "action");
|
|
9911
|
-
return entry ? /* @__PURE__ */
|
|
10957
|
+
return entry ? /* @__PURE__ */ import_react64.default.createElement(ActionView, { entry, messageId: props.messageId }) : null;
|
|
9912
10958
|
}
|
|
9913
10959
|
ctx.effect(() => {
|
|
9914
10960
|
const style = document.createElement("style");
|
|
@@ -9924,6 +10970,8 @@ function apply(ctx) {
|
|
|
9924
10970
|
);
|
|
9925
10971
|
ctx.effect(() => {
|
|
9926
10972
|
const stop = () => {
|
|
10973
|
+
speechMemory.clear();
|
|
10974
|
+
for (const entry of controllers.values()) entry.speechState.checkpoint = null;
|
|
9927
10975
|
ownership.cancel();
|
|
9928
10976
|
void meeting.end();
|
|
9929
10977
|
for (const entry of controllers.values()) {
|
|
@@ -9974,7 +11022,7 @@ function apply(ctx) {
|
|
|
9974
11022
|
};
|
|
9975
11023
|
const refreshCapabilities = () => {
|
|
9976
11024
|
for (const entry of controllers.values())
|
|
9977
|
-
run(entry.controller, entry.controller.refreshCapabilities());
|
|
11025
|
+
run(entry.controller, entry.controller.refreshCapabilities({ localOnly: true }));
|
|
9978
11026
|
document.dispatchEvent(new Event("dsh-live-voice:capabilitieschanged"));
|
|
9979
11027
|
};
|
|
9980
11028
|
const visibilityChanged = () => {
|
|
@@ -9990,6 +11038,7 @@ function apply(ctx) {
|
|
|
9990
11038
|
return () => {
|
|
9991
11039
|
disposed = true;
|
|
9992
11040
|
ownership.close();
|
|
11041
|
+
speechMemory.clear();
|
|
9993
11042
|
window.speechSynthesis?.removeEventListener?.("voiceschanged", refreshCapabilities);
|
|
9994
11043
|
navigator.mediaDevices?.removeEventListener?.("devicechange", refreshCapabilities);
|
|
9995
11044
|
document.removeEventListener("visibilitychange", visibilityChanged);
|