@omniloy/sofia-sdk 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4742,7 +4742,7 @@ const {
4742
4742
  create: create$1,
4743
4743
  } = axios;
4744
4744
 
4745
- const version$2 = "1.0.6";
4745
+ const version$2 = "1.0.7";
4746
4746
 
4747
4747
  const handleApiError$1 = async (error) => {
4748
4748
  return Promise.reject(error);
@@ -5063,6 +5063,10 @@ var SettingsApiKeys = /* @__PURE__ */ ((SettingsApiKeys2) => {
5063
5063
  SettingsApiKeys2["templateId"] = "templateId";
5064
5064
  SettingsApiKeys2["summary"] = "summary";
5065
5065
  SettingsApiKeys2["showConsentIndicator"] = "showConsentIndicator";
5066
+ SettingsApiKeys2["showInsertionPreview"] = "showInsertionPreview";
5067
+ SettingsApiKeys2["showChatWithVoice"] = "showChatWithVoice";
5068
+ SettingsApiKeys2["transcriberUrl"] = "transcriberUrl";
5069
+ SettingsApiKeys2["vadMinCoverage"] = "vadMinCoverage";
5066
5070
  return SettingsApiKeys2;
5067
5071
  })(SettingsApiKeys || {});
5068
5072
 
@@ -5121,7 +5125,10 @@ const SettingsApi = {
5121
5125
  [SettingsApiKeys.template]: profileResponse.template,
5122
5126
  [SettingsApiKeys.baseTemplate]: profileResponse.baseTemplate,
5123
5127
  [SettingsApiKeys.summary]: profileResponse.summary,
5124
- [SettingsApiKeys.showConsentIndicator]: profileResponse.showConsentIndicator
5128
+ [SettingsApiKeys.showConsentIndicator]: profileResponse.showConsentIndicator,
5129
+ [SettingsApiKeys.showInsertionPreview]: profileResponse.showInsertionPreview,
5130
+ [SettingsApiKeys.showChatWithVoice]: profileResponse.showChatWithVoice,
5131
+ [SettingsApiKeys.transcriberUrl]: profileResponse.transcriberUrl
5125
5132
  };
5126
5133
  return mappedResponse;
5127
5134
  }
@@ -5415,6 +5422,7 @@ const ar = {
5415
5422
  "View transcription": "عرض النص المكتوب",
5416
5423
  "Generate anyway": "إنشاء على أي حال",
5417
5424
  "Audio lost (~{duration}s)": "صوت مفقود (~{duration}ث)",
5425
+ "Room and microphone status": "حالة الغرفة والميكروفون",
5418
5426
  };
5419
5427
 
5420
5428
  const Add$b = "Afegir";
@@ -5721,6 +5729,7 @@ const ca = {
5721
5729
  "View transcription": "Veure transcripció",
5722
5730
  "Generate anyway": "Generar igualment",
5723
5731
  "Audio lost (~{duration}s)": "Àudio perdut (~{duration}s)",
5732
+ "Room and microphone status": "Estat de la sala i el micròfon",
5724
5733
  };
5725
5734
 
5726
5735
  const Add$a = "Afegir";
@@ -6027,6 +6036,7 @@ const ca_valencia = {
6027
6036
  "View transcription": "Veure transcripció",
6028
6037
  "Generate anyway": "Generar igualment",
6029
6038
  "Audio lost (~{duration}s)": "Àudio perdut (~{duration}s)",
6039
+ "Room and microphone status": "Estat de la sala i el micròfon",
6030
6040
  };
6031
6041
 
6032
6042
  const Add$9 = "Přidat";
@@ -6333,6 +6343,7 @@ const cs = {
6333
6343
  "View transcription": "Zobrazit přepis",
6334
6344
  "Generate anyway": "Vygenerovat přesto",
6335
6345
  "Audio lost (~{duration}s)": "Ztracený zvuk (~{duration}s)",
6346
+ "Room and microphone status": "Stav místnosti a mikrofonu",
6336
6347
  };
6337
6348
 
6338
6349
  const Add$8 = "Add";
@@ -6639,6 +6650,7 @@ const en_GB = {
6639
6650
  "View transcription": "View transcription",
6640
6651
  "Generate anyway": "Generate anyway",
6641
6652
  "Audio lost (~{duration}s)": "Audio lost (~{duration}s)",
6653
+ "Room and microphone status": "Room and microphone status",
6642
6654
  };
6643
6655
 
6644
6656
  const Add$7 = "Add";
@@ -6946,6 +6958,7 @@ const en_US = {
6946
6958
  "View transcription": "View transcription",
6947
6959
  "Generate anyway": "Generate anyway",
6948
6960
  "Audio lost (~{duration}s)": "Audio lost (~{duration}s)",
6961
+ "Room and microphone status": "Room and microphone status",
6949
6962
  };
6950
6963
 
6951
6964
  const Add$6 = "Añadir";
@@ -7252,6 +7265,7 @@ const es = {
7252
7265
  "View transcription": "Ver transcripción",
7253
7266
  "Generate anyway": "Generar igualmente",
7254
7267
  "Audio lost (~{duration}s)": "Audio perdido (~{duration}s)",
7268
+ "Room and microphone status": "Estado de la sala y el micrófono",
7255
7269
  };
7256
7270
 
7257
7271
  const Add$5 = "Ajouter";
@@ -7558,6 +7572,7 @@ const fr = {
7558
7572
  "View transcription": "Voir la transcription",
7559
7573
  "Generate anyway": "Générer quand même",
7560
7574
  "Audio lost (~{duration}s)": "Audio perdu (~{duration}s)",
7575
+ "Room and microphone status": "État de la salle et du microphone",
7561
7576
  };
7562
7577
 
7563
7578
  const Add$4 = "जोड़ें";
@@ -7843,6 +7858,7 @@ const hi = {
7843
7858
  "View transcription": "ट्रांसक्रिप्शन देखें",
7844
7859
  "Generate anyway": "फिर भी उत्पन्न करें",
7845
7860
  "Audio lost (~{duration}s)": "ऑडियो खो गया (~{duration}सेकंड)",
7861
+ "Room and microphone status": "कमरे और माइक्रोफ़ोन की स्थिति",
7846
7862
  };
7847
7863
 
7848
7864
  const Add$3 = "Tambahkan";
@@ -8127,6 +8143,7 @@ const id = {
8127
8143
  "View transcription": "Lihat transkripsi",
8128
8144
  "Generate anyway": "Generate tetap",
8129
8145
  "Audio lost (~{duration}s)": "Audio hilang (~{duration}d)",
8146
+ "Room and microphone status": "Status ruangan dan mikrofon",
8130
8147
  };
8131
8148
 
8132
8149
  const Add$2 = "ਸ਼ਾਮਲ ਕਰੋ";
@@ -8433,6 +8450,7 @@ const pa = {
8433
8450
  "View transcription": "ਟ੍ਰਾਂਸਕ੍ਰਿਪਸ਼ਨ ਦੇਖੋ",
8434
8451
  "Generate anyway": "ਫਿਰ ਵੀ ਜਨਰੇਟ ਕਰੋ",
8435
8452
  "Audio lost (~{duration}s)": "ਆਡੀਓ ਗੁਆਚਿਆ (~{duration}ਸ)",
8453
+ "Room and microphone status": "ਕਮਰੇ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਦੀ ਸਥਿਤੀ",
8436
8454
  };
8437
8455
 
8438
8456
  const Add$1 = "Lägg till";
@@ -8739,6 +8757,7 @@ const sv = {
8739
8757
  "View transcription": "Visa transkription",
8740
8758
  "Generate anyway": "Generera ändå",
8741
8759
  "Audio lost (~{duration}s)": "Förlorat ljud (~{duration}s)",
8760
+ "Room and microphone status": "Rummets och mikrofonens status",
8742
8761
  };
8743
8762
 
8744
8763
  const Add = "شامل کریں";
@@ -9046,6 +9065,7 @@ const ur = {
9046
9065
  "View transcription": "ٹرانسکرپشن دیکھیں",
9047
9066
  "Generate anyway": "بہرحال تخلیق کریں",
9048
9067
  "Audio lost (~{duration}s)": "آڈیو ضائع ہوا (~{duration}سیکنڈ)",
9068
+ "Room and microphone status": "کمرے اور مائیکروفون کی حالت",
9049
9069
  };
9050
9070
 
9051
9071
  var LanguageCode = /* @__PURE__ */ ((LanguageCode2) => {
@@ -9405,6 +9425,9 @@ function parseProfileResponse(profile, predefinedLanguage) {
9405
9425
  } : null;
9406
9426
  const baseTemplate = profile?.[SettingsApiKeys.baseTemplate] ? profile[SettingsApiKeys.baseTemplate] : {};
9407
9427
  const showConsentIndicator = profile?.[SettingsApiKeys.showConsentIndicator] === true;
9428
+ const showInsertionPreview = profile?.[SettingsApiKeys.showInsertionPreview] === true;
9429
+ const showChatWithVoice = profile?.[SettingsApiKeys.showChatWithVoice] === true;
9430
+ const transcriberUrl = profile?.[SettingsApiKeys.transcriberUrl] || void 0;
9408
9431
  return {
9409
9432
  dictionary,
9410
9433
  language,
@@ -9415,7 +9438,10 @@ function parseProfileResponse(profile, predefinedLanguage) {
9415
9438
  summary,
9416
9439
  customTemplate,
9417
9440
  baseTemplate,
9418
- showConsentIndicator
9441
+ showConsentIndicator,
9442
+ showInsertionPreview,
9443
+ showChatWithVoice,
9444
+ transcriberUrl
9419
9445
  };
9420
9446
  }
9421
9447
  function getDefaultSettingsState() {
@@ -9429,7 +9455,10 @@ function getDefaultSettingsState() {
9429
9455
  summary: null,
9430
9456
  customTemplate: null,
9431
9457
  baseTemplate: {},
9432
- showConsentIndicator: false
9458
+ showConsentIndicator: false,
9459
+ showInsertionPreview: false,
9460
+ showChatWithVoice: false,
9461
+ transcriberUrl: void 0
9433
9462
  };
9434
9463
  }
9435
9464
 
@@ -9719,6 +9748,82 @@ const useSettingsTemplate = ({
9719
9748
  };
9720
9749
  };
9721
9750
 
9751
+ const VadCoverageApi = {
9752
+ /**
9753
+ * Fetch the available options plus the user's current selection. Returns
9754
+ * `null` on failure so callers can degrade gracefully (no selector, and the
9755
+ * transcriber resolves the value via API/default).
9756
+ */
9757
+ getOptions: async () => {
9758
+ try {
9759
+ const response = await requester.get(
9760
+ "/profiles/settings/vad-coverage/options"
9761
+ );
9762
+ if (response && Array.isArray(response.options)) {
9763
+ return response;
9764
+ }
9765
+ return null;
9766
+ } catch (error) {
9767
+ handleSettingsApiError(error, "Failed to fetch VAD coverage options");
9768
+ return null;
9769
+ }
9770
+ }
9771
+ };
9772
+
9773
+ const EMPTY_STATE = {
9774
+ options: [],
9775
+ selected: null,
9776
+ value: null
9777
+ };
9778
+ const useVadCoverage = () => {
9779
+ const [state, setState] = React.useState(EMPTY_STATE);
9780
+ const mountedRef = React.useRef(true);
9781
+ const loadVadCoverage = React.useCallback(async () => {
9782
+ const response = await VadCoverageApi.getOptions();
9783
+ if (!mountedRef.current) return;
9784
+ setState(
9785
+ response ? {
9786
+ options: response.options,
9787
+ selected: response.selected,
9788
+ value: response.value
9789
+ } : EMPTY_STATE
9790
+ );
9791
+ }, []);
9792
+ React.useEffect(() => {
9793
+ mountedRef.current = true;
9794
+ loadVadCoverage();
9795
+ return () => {
9796
+ mountedRef.current = false;
9797
+ };
9798
+ }, [loadVadCoverage]);
9799
+ const updateVadCoverage = React.useCallback(
9800
+ async (key) => {
9801
+ const option = state.options.find((o) => o.key === key);
9802
+ setState((prev) => ({
9803
+ ...prev,
9804
+ selected: key,
9805
+ value: option ? option.value : prev.value
9806
+ }));
9807
+ try {
9808
+ await SettingsApi.updateSetting(SettingsApiKeys.vadMinCoverage, key);
9809
+ } catch (error) {
9810
+ logger.settingsError("Error updating VAD coverage:", error);
9811
+ await loadVadCoverage();
9812
+ }
9813
+ },
9814
+ [state.options, loadVadCoverage]
9815
+ );
9816
+ const vadMinCoverageForSession = state.value ?? void 0;
9817
+ return {
9818
+ vadCoverageOptions: state.options,
9819
+ vadCoverageSelected: state.selected,
9820
+ vadCoverageValue: state.value,
9821
+ vadMinCoverageForSession,
9822
+ updateVadCoverage,
9823
+ loadVadCoverage
9824
+ };
9825
+ };
9826
+
9722
9827
  const SettingsContext = React__default.createContext(
9723
9828
  void 0
9724
9829
  );
@@ -9746,6 +9851,9 @@ const SettingsProvider = ({ predefinedLanguage, templateId, toolArgs, children }
9746
9851
  const [baseTemplate, setBaseTemplate] = React__default.useState({});
9747
9852
  const [customTemplate, setCustomTemplate] = React__default.useState(null);
9748
9853
  const [showConsentIndicator, setShowConsentIndicator] = React__default.useState(false);
9854
+ const [showInsertionPreview, setShowInsertionPreview] = React__default.useState(false);
9855
+ const [showChatWithVoice, setShowChatWithVoice] = React__default.useState(false);
9856
+ const [transcriberUrl, setTranscriberUrl] = React__default.useState(void 0);
9749
9857
  const [isLoading, setIsLoading] = React__default.useState(true);
9750
9858
  const isInitializedRef = React__default.useRef(false);
9751
9859
  const applySettings = React__default.useCallback(
@@ -9760,6 +9868,9 @@ const SettingsProvider = ({ predefinedLanguage, templateId, toolArgs, children }
9760
9868
  setCustomTemplate(parsed.customTemplate);
9761
9869
  setBaseTemplate(parsed.baseTemplate);
9762
9870
  setShowConsentIndicator(parsed.showConsentIndicator);
9871
+ setShowInsertionPreview(parsed.showInsertionPreview);
9872
+ setShowChatWithVoice(parsed.showChatWithVoice);
9873
+ setTranscriberUrl(parsed.transcriberUrl);
9763
9874
  const cache = SettingsCache.getInstance();
9764
9875
  cache.setDictionary(parsed.dictionary);
9765
9876
  cache.setLanguage(parsed.language);
@@ -9788,6 +9899,9 @@ const SettingsProvider = ({ predefinedLanguage, templateId, toolArgs, children }
9788
9899
  setCustomTemplate(defaults.customTemplate);
9789
9900
  setBaseTemplate(defaults.baseTemplate);
9790
9901
  setShowConsentIndicator(defaults.showConsentIndicator);
9902
+ setShowInsertionPreview(defaults.showInsertionPreview);
9903
+ setShowChatWithVoice(defaults.showChatWithVoice);
9904
+ setTranscriberUrl(defaults.transcriberUrl);
9791
9905
  SettingsCache.getInstance().clear();
9792
9906
  } finally {
9793
9907
  setIsLoading(false);
@@ -9828,6 +9942,7 @@ const SettingsProvider = ({ predefinedLanguage, templateId, toolArgs, children }
9828
9942
  customTemplate,
9829
9943
  baseTemplate
9830
9944
  });
9945
+ const vad = useVadCoverage();
9831
9946
  const sendSummaryMessage = React__default.useCallback(() => {
9832
9947
  if (!summary || !summary.isEnabled) return;
9833
9948
  window.dispatchEvent(new CustomEvent("sendSummaryMessage"));
@@ -9869,6 +9984,13 @@ const SettingsProvider = ({ predefinedLanguage, templateId, toolArgs, children }
9869
9984
  customTemplate,
9870
9985
  baseTemplate,
9871
9986
  showConsentIndicator,
9987
+ showInsertionPreview,
9988
+ showChatWithVoice,
9989
+ transcriberUrl,
9990
+ vadCoverageOptions: vad.vadCoverageOptions,
9991
+ vadCoverageSelected: vad.vadCoverageSelected,
9992
+ vadCoverageValue: vad.vadCoverageValue,
9993
+ vadMinCoverageForSession: vad.vadMinCoverageForSession,
9872
9994
  getTemplateId: templateHelpers.getTemplateId,
9873
9995
  getMixedToolArgs: templateHelpers.getMixedToolArgs,
9874
9996
  updateDictionary: actions.updateDictionary,
@@ -9877,6 +9999,7 @@ const SettingsProvider = ({ predefinedLanguage, templateId, toolArgs, children }
9877
9999
  updateSources: actions.updateSources,
9878
10000
  updatePreferredMicrophone: actions.updatePreferredMicrophone,
9879
10001
  updateSummary: actions.updateSummary,
10002
+ updateVadCoverage: vad.updateVadCoverage,
9880
10003
  sendSummaryMessage,
9881
10004
  updateSettings: actions.updateSettings,
9882
10005
  refreshSettings,
@@ -9896,6 +10019,14 @@ const SettingsProvider = ({ predefinedLanguage, templateId, toolArgs, children }
9896
10019
  customTemplate,
9897
10020
  baseTemplate,
9898
10021
  showConsentIndicator,
10022
+ showInsertionPreview,
10023
+ showChatWithVoice,
10024
+ transcriberUrl,
10025
+ vad.vadCoverageOptions,
10026
+ vad.vadCoverageSelected,
10027
+ vad.vadCoverageValue,
10028
+ vad.vadMinCoverageForSession,
10029
+ vad.updateVadCoverage,
9899
10030
  templateHelpers.getTemplateId,
9900
10031
  templateHelpers.getMixedToolArgs,
9901
10032
  actions,
@@ -16371,6 +16502,17 @@ const useToastContext = createContextHook(
16371
16502
  "ToastProvider"
16372
16503
  );
16373
16504
 
16505
+ const appendClientVersion = (url) => {
16506
+ if (!url) return url;
16507
+ try {
16508
+ const parsed = new URL(url);
16509
+ parsed.searchParams.set("client_version", version$2);
16510
+ return parsed.toString();
16511
+ } catch {
16512
+ return url;
16513
+ }
16514
+ };
16515
+
16374
16516
  const initialState$1 = {
16375
16517
  socket: null,
16376
16518
  stream: null,
@@ -16652,7 +16794,7 @@ const restoreDeepWithPairs = (value, pairs) => {
16652
16794
  };
16653
16795
 
16654
16796
  const AudioRecorderApi = {
16655
- record: (socket, uuid, language, extractionConfig, templateId, medicalPractice, anonymization) => {
16797
+ record: (socket, uuid, language, extractionConfig, templateId, medicalPractice, anonymization, vadMinCoverage) => {
16656
16798
  const recordCommand = {
16657
16799
  uid: uuid,
16658
16800
  language,
@@ -16660,6 +16802,7 @@ const AudioRecorderApi = {
16660
16802
  model: "medium",
16661
16803
  medical_practice: medicalPractice || "medical",
16662
16804
  use_vad: true,
16805
+ ...vadMinCoverage !== void 0 ? { vad_min_coverage: vadMinCoverage } : {},
16663
16806
  ...templateId ? { template_id: templateId } : {},
16664
16807
  ...anonymization?.length ? { anonymization } : {},
16665
16808
  ...extractionConfig?.enabled && {
@@ -16855,6 +16998,7 @@ const useWebSocketConnection = ({
16855
16998
  templateId,
16856
16999
  medicalPractice,
16857
17000
  anonymizationMap,
17001
+ vadMinCoverage,
16858
17002
  buildPreviousContext
16859
17003
  }) => {
16860
17004
  const onUnexpectedCloseRef = React.useRef(onUnexpectedClose);
@@ -17017,6 +17161,13 @@ const useWebSocketConnection = ({
17017
17161
  }, [extractionConfig]);
17018
17162
  const startRecording = React.useCallback(
17019
17163
  async (mediaStream) => {
17164
+ if (!wssUrl) {
17165
+ logger.error(
17166
+ 'Cannot start recording: no transcriber URL available. Configure "transcriberUrl" in the profile settings.'
17167
+ );
17168
+ mediaStream?.getTracks().forEach((track) => track.stop());
17169
+ return;
17170
+ }
17020
17171
  const newUuid = generateUUID();
17021
17172
  setUuid(newUuid);
17022
17173
  const wssLanguage = await getTranscriptionLanguage() || language;
@@ -17075,7 +17226,7 @@ const useWebSocketConnection = ({
17075
17226
  if (isUnexpected) {
17076
17227
  if (event.code === 1006) {
17077
17228
  logger.webSocketError(
17078
- "WSS URL is unreachable. Please verify your wssurl property points to a valid WebSocket endpoint."
17229
+ 'WSS URL is unreachable. Please verify the "transcriberUrl" configured in the profile settings points to a valid WebSocket endpoint.'
17079
17230
  );
17080
17231
  }
17081
17232
  onUnexpectedCloseRef.current?.(event);
@@ -17096,7 +17247,8 @@ const useWebSocketConnection = ({
17096
17247
  config,
17097
17248
  templateId,
17098
17249
  medicalPractice,
17099
- anonymizationMap
17250
+ anonymizationMap,
17251
+ vadMinCoverage
17100
17252
  );
17101
17253
  }).catch(() => {
17102
17254
  AudioRecorderApi.record(
@@ -17106,7 +17258,8 @@ const useWebSocketConnection = ({
17106
17258
  extractionConfig,
17107
17259
  templateId,
17108
17260
  medicalPractice,
17109
- anonymizationMap
17261
+ anonymizationMap,
17262
+ vadMinCoverage
17110
17263
  );
17111
17264
  });
17112
17265
  } catch (error) {
@@ -17220,6 +17373,9 @@ const useWebSocketConnection = ({
17220
17373
  model: "medium",
17221
17374
  medical_practice: medicalPractice || "medical",
17222
17375
  use_vad: true,
17376
+ // Only forward an explicit user selection; when undefined the
17377
+ // transcriber resolves the value via API/default (SOF-707).
17378
+ ...vadMinCoverage !== void 0 ? { vad_min_coverage: vadMinCoverage } : {},
17223
17379
  ...templateId ? { template_id: templateId } : {},
17224
17380
  ...anonymizationMap?.length && {
17225
17381
  anonymization: anonymizationMap
@@ -17263,7 +17419,8 @@ const useWebSocketConnection = ({
17263
17419
  extractionConfig,
17264
17420
  templateId,
17265
17421
  medicalPractice,
17266
- anonymizationMap
17422
+ anonymizationMap,
17423
+ vadMinCoverage
17267
17424
  ]
17268
17425
  );
17269
17426
  return { startRecording };
@@ -18524,8 +18681,12 @@ const useAudioRecording = (options = {}) => {
18524
18681
  chatMicrophoneActive,
18525
18682
  setState
18526
18683
  } = useTranscriptorContext();
18527
- const { wssUrl, apiKey, hasTemplateConfig } = useApiConfigContext();
18528
- const { language, getTemplateId } = useSettingsContext();
18684
+ const { apiKey, hasTemplateConfig } = useApiConfigContext();
18685
+ const { language, getTemplateId, vadMinCoverageForSession, transcriberUrl } = useSettingsContext();
18686
+ const wssUrl = React.useMemo(
18687
+ () => appendClientVersion(transcriberUrl ?? ""),
18688
+ [transcriberUrl]
18689
+ );
18529
18690
  const { trackEvent } = useEventTracker();
18530
18691
  const trackEventRef = React.useRef(trackEvent);
18531
18692
  React.useEffect(() => {
@@ -18823,6 +18984,7 @@ const useAudioRecording = (options = {}) => {
18823
18984
  templateId: resolvedTemplateId,
18824
18985
  medicalPractice,
18825
18986
  anonymizationMap,
18987
+ vadMinCoverage: vadMinCoverageForSession,
18826
18988
  buildPreviousContext
18827
18989
  });
18828
18990
  const { cleanupPromise } = useAudioRecordingCleanup();
@@ -19270,7 +19432,7 @@ const useAudioRecording = (options = {}) => {
19270
19432
  slowConnectionMessage
19271
19433
  ]);
19272
19434
  const noTemplateConfig = !hasTemplateConfig;
19273
- const isDisabled = disabled || connectionLoading || chatMicrophoneActive || noTemplateConfig;
19435
+ const isDisabled = disabled || connectionLoading || chatMicrophoneActive || noTemplateConfig || !wssUrl;
19274
19436
  return {
19275
19437
  stream: state.stream,
19276
19438
  socket: state.socket,
@@ -147442,7 +147604,8 @@ const useConfigurationLogic = (currentScreen, setCurrentScreen) => {
147442
147604
  const CustomSelect = ({
147443
147605
  options,
147444
147606
  onChange,
147445
- selectedNumber = 0
147607
+ selectedNumber = 0,
147608
+ disabled = false
147446
147609
  }) => {
147447
147610
  const dropdownRef = React.useRef(null);
147448
147611
  const [selected, setSelected] = React.useState(options[selectedNumber]);
@@ -147474,6 +147637,9 @@ const CustomSelect = ({
147474
147637
  React.useEffect(() => {
147475
147638
  setSelected(options[selectedNumber]);
147476
147639
  }, [selectedNumber, options]);
147640
+ React.useEffect(() => {
147641
+ if (disabled) setIsOpen(false);
147642
+ }, [disabled]);
147477
147643
  return /* @__PURE__ */ jsxs("div", { ref: dropdownRef, className: "omniscribe_select-container", children: [
147478
147644
  /* @__PURE__ */ jsxs(
147479
147645
  "button",
@@ -147481,6 +147647,7 @@ const CustomSelect = ({
147481
147647
  type: "button",
147482
147648
  className: "omniscribe_select-button text-p",
147483
147649
  onClick: () => setIsOpen(!isOpen),
147650
+ disabled,
147484
147651
  children: [
147485
147652
  /* @__PURE__ */ jsxs("span", { className: "omniscribe_select-text", children: [
147486
147653
  selected.icon,
@@ -147502,7 +147669,7 @@ const CustomSelect = ({
147502
147669
  ]
147503
147670
  }
147504
147671
  ),
147505
- isOpen && /* @__PURE__ */ jsx$2("div", { className: "omniscribe_select-content-container", children: /* @__PURE__ */ jsx$2("ul", { className: "omniscribe_select-content-ul scrollbar-pretty", children: options.map((option) => /* @__PURE__ */ jsxs(
147672
+ isOpen && !disabled && /* @__PURE__ */ jsx$2("div", { className: "omniscribe_select-content-container", children: /* @__PURE__ */ jsx$2("ul", { className: "omniscribe_select-content-ul scrollbar-pretty", children: options.map((option) => /* @__PURE__ */ jsxs(
147506
147673
  "li",
147507
147674
  {
147508
147675
  onMouseDown: (e) => {
@@ -147827,13 +147994,87 @@ const CustomMicrophoneSelector = ({ onChange }) => {
147827
147994
  return /* @__PURE__ */ jsx$2(SelectWithPermissionHandling, {});
147828
147995
  };
147829
147996
 
147997
+ const FALLBACK_LOCALE = LanguageCode.en_US;
147998
+ const getLocalizedText = (text, language) => {
147999
+ if (!text) return "";
148000
+ return text[language] ?? text[FALLBACK_LOCALE] ?? Object.values(text)[0] ?? "";
148001
+ };
148002
+ const getVadCoverageLabel = (option, language) => getLocalizedText(option.label, language);
148003
+ const getVadCoverageDescription = (option, language) => getLocalizedText(option.description, language);
148004
+
148005
+ const AudioEnvironmentSelector = () => {
148006
+ const { formatMessage } = useIntl();
148007
+ const {
148008
+ language,
148009
+ vadCoverageOptions,
148010
+ vadCoverageSelected,
148011
+ updateVadCoverage
148012
+ } = useSettingsContext();
148013
+ const { enabled, connectionLoading } = useTranscriptorContext();
148014
+ const { trackEvent } = useEventTracker();
148015
+ const disabled = enabled || connectionLoading;
148016
+ const options = React__default.useMemo(
148017
+ () => vadCoverageOptions.map((o) => ({
148018
+ value: o.key,
148019
+ label: getVadCoverageLabel(o, language)
148020
+ })),
148021
+ [vadCoverageOptions, language]
148022
+ );
148023
+ const selectedIndex = React__default.useMemo(() => {
148024
+ const index = vadCoverageOptions.findIndex(
148025
+ (o) => o.key === vadCoverageSelected
148026
+ );
148027
+ return index >= 0 ? index : 0;
148028
+ }, [vadCoverageOptions, vadCoverageSelected]);
148029
+ const selectedOption = vadCoverageOptions[selectedIndex];
148030
+ const handleChange = React__default.useCallback(
148031
+ (key) => {
148032
+ updateVadCoverage(key);
148033
+ trackEvent("click", "select_audio_environment", { value: key });
148034
+ },
148035
+ [updateVadCoverage, trackEvent]
148036
+ );
148037
+ if (vadCoverageOptions.length === 0) return null;
148038
+ return /* @__PURE__ */ jsxs("div", { className: "omniscribe_config-audio-env", children: [
148039
+ /* @__PURE__ */ jsx$2("p", { className: "omniscribe_config-section-label", children: formatMessage({ id: "Room and microphone status" }) }),
148040
+ /* @__PURE__ */ jsx$2("div", { className: "w-full", "data-testid": "audio-environment-selector", children: /* @__PURE__ */ jsx$2(
148041
+ CustomSelect,
148042
+ {
148043
+ options,
148044
+ onChange: handleChange,
148045
+ selectedNumber: selectedIndex,
148046
+ disabled,
148047
+ className: "w-full"
148048
+ }
148049
+ ) }),
148050
+ selectedOption && /* @__PURE__ */ jsx$2("p", { className: "omniscribe_config-subscreen-subdescription", children: getVadCoverageDescription(selectedOption, language) })
148051
+ ] });
148052
+ };
148053
+
148054
+ const ConfigSection = ({
148055
+ description,
148056
+ children,
148057
+ className = ""
148058
+ }) => {
148059
+ return /* @__PURE__ */ jsxs("div", { className: `omniscribe_config-language-section ${className}`.trim(), children: [
148060
+ description && /* @__PURE__ */ jsx$2("p", { className: "omniscribe_config-subscreen-description", children: description }),
148061
+ children
148062
+ ] });
148063
+ };
148064
+
147830
148065
  const Microphone = () => {
147831
148066
  const { formatMessage } = useIntl();
147832
148067
  return /* @__PURE__ */ jsxs("div", { className: "omniscribe_config-content", children: [
147833
148068
  /* @__PURE__ */ jsx$2(SubscreenHeader, { title: formatMessage({ id: "Microphone options" }) }),
147834
148069
  /* @__PURE__ */ jsxs("div", { className: "omniscribe_config-subscreen-content", children: [
147835
- /* @__PURE__ */ jsx$2("p", { className: "omniscribe_config-subscreen-description", children: formatMessage({ id: "Select the input microphone" }) }),
147836
- /* @__PURE__ */ jsx$2(CustomMicrophoneSelector, {})
148070
+ /* @__PURE__ */ jsx$2(
148071
+ ConfigSection,
148072
+ {
148073
+ description: formatMessage({ id: "Select the input microphone" }),
148074
+ children: /* @__PURE__ */ jsx$2(CustomMicrophoneSelector, {})
148075
+ }
148076
+ ),
148077
+ /* @__PURE__ */ jsx$2(AudioEnvironmentSelector, {})
147837
148078
  ] }),
147838
148079
  /* @__PURE__ */ jsx$2(VersionSection, {})
147839
148080
  ] });
@@ -147893,17 +148134,6 @@ const TranscriptionLanguageSelector = () => {
147893
148134
  ) });
147894
148135
  };
147895
148136
 
147896
- const ConfigSection = ({
147897
- description,
147898
- children,
147899
- className = ""
147900
- }) => {
147901
- return /* @__PURE__ */ jsxs("div", { className: `omniscribe_config-language-section ${className}`.trim(), children: [
147902
- description && /* @__PURE__ */ jsx$2("p", { className: "omniscribe_config-subscreen-description", children: description }),
147903
- children
147904
- ] });
147905
- };
147906
-
147907
148137
  const Language = () => {
147908
148138
  const { formatMessage } = useIntl();
147909
148139
  return /* @__PURE__ */ jsxs("div", { className: "omniscribe_config-content", children: [
@@ -150491,20 +150721,9 @@ function ProcessingThreadsProvider({
150491
150721
  return /* @__PURE__ */ jsx$2(ProcessingThreadsContext.Provider, { value, children });
150492
150722
  }
150493
150723
 
150494
- const appendClientVersion = (url) => {
150495
- if (!url) return url;
150496
- try {
150497
- const parsed = new URL(url);
150498
- parsed.searchParams.set("client_version", version$2);
150499
- return parsed.toString();
150500
- } catch {
150501
- return url;
150502
- }
150503
- };
150504
150724
  const ApiConfigProvider = ({
150505
150725
  children,
150506
150726
  clientBaseUrl,
150507
- clientWssUrl,
150508
150727
  clientApiKey,
150509
150728
  isOpen,
150510
150729
  setIsOpen,
@@ -150512,9 +150731,8 @@ const ApiConfigProvider = ({
150512
150731
  userMedicalSpecialty,
150513
150732
  patientId
150514
150733
  }) => {
150515
- const [{ baseUrl, langGraphBaseUrl, apiKey, wssUrl }, setConfig] = React.useState({
150734
+ const [{ baseUrl, langGraphBaseUrl, apiKey }, setConfig] = React.useState({
150516
150735
  baseUrl: clientBaseUrl,
150517
- wssUrl: appendClientVersion(clientWssUrl),
150518
150736
  langGraphBaseUrl: clientBaseUrl + "/lang-graph/",
150519
150737
  apiKey: clientApiKey
150520
150738
  });
@@ -150525,16 +150743,14 @@ const ApiConfigProvider = ({
150525
150743
  if (clientBaseUrl && clientApiKey) {
150526
150744
  setConfig({
150527
150745
  baseUrl: clientBaseUrl,
150528
- wssUrl: appendClientVersion(clientWssUrl),
150529
150746
  langGraphBaseUrl: clientBaseUrl + "/lang-graph/",
150530
150747
  apiKey: clientApiKey
150531
150748
  });
150532
150749
  }
150533
- }, [clientApiKey, clientBaseUrl, clientWssUrl]);
150750
+ }, [clientApiKey, clientBaseUrl]);
150534
150751
  const contextValue = React.useMemo(
150535
150752
  () => ({
150536
150753
  baseUrl,
150537
- wssUrl,
150538
150754
  langGraphBaseUrl,
150539
150755
  apiKey,
150540
150756
  isOmniOpen,
@@ -150546,7 +150762,6 @@ const ApiConfigProvider = ({
150546
150762
  }),
150547
150763
  [
150548
150764
  baseUrl,
150549
- wssUrl,
150550
150765
  langGraphBaseUrl,
150551
150766
  apiKey,
150552
150767
  isOmniOpen,
@@ -150624,6 +150839,32 @@ const I18nProvider = ({
150624
150839
  );
150625
150840
  };
150626
150841
 
150842
+ const TranscriberUrlSignal = () => {
150843
+ const { transcriberUrl, isLoading } = useSettingsContext();
150844
+ const ref = React.useRef(null);
150845
+ const missingWarnedRef = React.useRef(false);
150846
+ React.useEffect(() => {
150847
+ if (isLoading) return;
150848
+ if (transcriberUrl) {
150849
+ ref.current?.dispatchEvent(
150850
+ new CustomEvent("sofia:transcriber-url-changed", {
150851
+ bubbles: true,
150852
+ composed: true,
150853
+ detail: { url: transcriberUrl }
150854
+ })
150855
+ );
150856
+ return;
150857
+ }
150858
+ if (!missingWarnedRef.current) {
150859
+ missingWarnedRef.current = true;
150860
+ logger.warn(
150861
+ '[Sofia SDK] No transcriber URL available: the settings API returned no "transcriberUrl". Audio recording will be disabled until one is configured in the profile settings.'
150862
+ );
150863
+ }
150864
+ }, [isLoading, transcriberUrl]);
150865
+ return /* @__PURE__ */ jsx$2("span", { ref, style: { display: "none" }, "aria-hidden": "true" });
150866
+ };
150867
+
150627
150868
  const calculateDuration = (transcript) => {
150628
150869
  if (!transcript || transcript.length === 0) return 0;
150629
150870
  const validEndTimes = transcript.map((segment) => parseFloat(segment.end)).filter((time) => !isNaN(time) && isFinite(time));
@@ -150775,11 +151016,6 @@ const Omniscribe = ({
150775
151016
  value: baseurl,
150776
151017
  description: "API base URL for backend communication"
150777
151018
  },
150778
- {
150779
- name: "wssurl",
150780
- value: wssurl,
150781
- description: "WebSocket URL for real-time communication"
150782
- },
150783
151019
  {
150784
151020
  name: "apikey",
150785
151021
  value: apikey,
@@ -150812,6 +151048,11 @@ const Omniscribe = ({
150812
151048
  }, [apikey]);
150813
151049
  React.useEffect(() => {
150814
151050
  const deprecatedProps = [
151051
+ {
151052
+ name: "wssurl",
151053
+ value: wssurl,
151054
+ message: 'The transcriber WebSocket URL is now resolved from the settings API ("transcriberUrl" in the profile settings).'
151055
+ },
150815
151056
  {
150816
151057
  name: "isonlychat",
150817
151058
  value: isonlychat,
@@ -150955,52 +151196,54 @@ const Omniscribe = ({
150955
151196
  }
150956
151197
  const selectorValues = typeof transcriptorselectvalues === "string" ? JSON.parse(transcriptorselectvalues) : transcriptorselectvalues;
150957
151198
  const patientData = typeof patientdata === "string" ? JSON.parse(patientdata) : patientdata;
150958
- if (!baseurl || !apikey || !wssurl || !patientid || patientid.trim() === "" || !userid || userid.trim() === "" || apikey.trim() === "" || wssurl.trim() === "" || baseurl.trim() === "")
151199
+ if (!baseurl || !apikey || !patientid || patientid.trim() === "" || !userid || userid.trim() === "" || apikey.trim() === "" || baseurl.trim() === "")
150959
151200
  return null;
150960
- return /* @__PURE__ */ jsx$2(
151201
+ return /* @__PURE__ */ jsx$2(Fragment, { children: /* @__PURE__ */ jsx$2(
150961
151202
  ApiConfigProvider,
150962
151203
  {
150963
151204
  clientApiKey: apikey,
150964
151205
  clientBaseUrl: baseurl,
150965
- clientWssUrl: wssurl,
150966
151206
  isOpen: isopen,
150967
151207
  setIsOpen,
150968
151208
  hasTemplateConfig,
150969
151209
  userMedicalSpecialty,
150970
151210
  patientId: patientid,
150971
- children: /* @__PURE__ */ jsx$2(
151211
+ children: /* @__PURE__ */ jsxs(
150972
151212
  SettingsProvider,
150973
151213
  {
150974
151214
  predefinedLanguage: safeLanguage,
150975
151215
  templateId: templateid,
150976
151216
  toolArgs: templateFields,
150977
- children: /* @__PURE__ */ jsx$2(I18nProvider, { children: /* @__PURE__ */ jsxs(SessionProvider, { children: [
150978
- /* @__PURE__ */ jsx$2(BrowserCapabilityProbe, {}),
150979
- /* @__PURE__ */ jsx$2(
150980
- TranscriptorProvider,
150981
- {
150982
- screenLoader: isscreenloading,
150983
- transcriptorSelectValues: selectorValues,
150984
- children: /* @__PURE__ */ jsx$2(
150985
- LangGraphProvider,
150986
- {
150987
- propsUserId: userid,
150988
- propsPatientId: patientid,
150989
- propsPatientData: patientData,
150990
- propsHandleReport: handleReport,
150991
- propsHandleFill: handleFill,
150992
- propsRenderReportContent: renderReportContent,
150993
- children: /* @__PURE__ */ jsx$2(ProcessingThreadsProvider, { children: /* @__PURE__ */ jsx$2(ThreadProvider, { children: /* @__PURE__ */ jsx$2(MessageImagesProvider, { children: /* @__PURE__ */ jsx$2(StreamProvider, { children: /* @__PURE__ */ jsx$2(ToastProvider, { toast, children: /* @__PURE__ */ jsx$2(App, {}) }) }) }) }) })
150994
- }
150995
- )
150996
- }
150997
- )
150998
- ] }) })
151217
+ children: [
151218
+ /* @__PURE__ */ jsx$2(TranscriberUrlSignal, {}),
151219
+ /* @__PURE__ */ jsx$2(I18nProvider, { children: /* @__PURE__ */ jsxs(SessionProvider, { children: [
151220
+ /* @__PURE__ */ jsx$2(BrowserCapabilityProbe, {}),
151221
+ /* @__PURE__ */ jsx$2(
151222
+ TranscriptorProvider,
151223
+ {
151224
+ screenLoader: isscreenloading,
151225
+ transcriptorSelectValues: selectorValues,
151226
+ children: /* @__PURE__ */ jsx$2(
151227
+ LangGraphProvider,
151228
+ {
151229
+ propsUserId: userid,
151230
+ propsPatientId: patientid,
151231
+ propsPatientData: patientData,
151232
+ propsHandleReport: handleReport,
151233
+ propsHandleFill: handleFill,
151234
+ propsRenderReportContent: renderReportContent,
151235
+ children: /* @__PURE__ */ jsx$2(ProcessingThreadsProvider, { children: /* @__PURE__ */ jsx$2(ThreadProvider, { children: /* @__PURE__ */ jsx$2(MessageImagesProvider, { children: /* @__PURE__ */ jsx$2(StreamProvider, { children: /* @__PURE__ */ jsx$2(ToastProvider, { toast, children: /* @__PURE__ */ jsx$2(App, {}) }) }) }) }) })
151236
+ }
151237
+ )
151238
+ }
151239
+ )
151240
+ ] }) })
151241
+ ]
150999
151242
  }
151000
151243
  )
151001
151244
  },
151002
151245
  componentKey
151003
- );
151246
+ ) });
151004
151247
  };
151005
151248
 
151006
151249
  var abapExports = requireAbap();