@omniloy/sofia-sdk 1.0.10 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/legacy/webcomponents.d.ts +155 -0
- package/dist/legacy/webcomponents.es.js +608 -287
- package/dist/legacy/webcomponents.umd.js +608 -287
- package/dist/react/index.d.ts +155 -0
- package/dist/react/index.es.js +411 -111
- package/dist/webcomponents.d.ts +155 -0
- package/dist/webcomponents.es.js +341 -17
- package/dist/webcomponents.umd.js +341 -17
- package/package.json +1 -1
package/dist/react/index.es.js
CHANGED
|
@@ -5145,7 +5145,7 @@ const {
|
|
|
5145
5145
|
create: create$1,
|
|
5146
5146
|
} = axios;
|
|
5147
5147
|
|
|
5148
|
-
const version$2 = "1.0.
|
|
5148
|
+
const version$2 = "1.0.11";
|
|
5149
5149
|
|
|
5150
5150
|
const handleApiError$1 = async (error) => {
|
|
5151
5151
|
return Promise.reject(error);
|
|
@@ -11078,6 +11078,141 @@ const useVadCoverage = () => {
|
|
|
11078
11078
|
};
|
|
11079
11079
|
};
|
|
11080
11080
|
|
|
11081
|
+
const FAMILIES = [
|
|
11082
|
+
"recording",
|
|
11083
|
+
"activity",
|
|
11084
|
+
"report",
|
|
11085
|
+
"lifecycle"
|
|
11086
|
+
];
|
|
11087
|
+
const familyOf = (name) => {
|
|
11088
|
+
const prefix = name.split(".")[0];
|
|
11089
|
+
return FAMILIES.includes(prefix) ? prefix : "lifecycle";
|
|
11090
|
+
};
|
|
11091
|
+
|
|
11092
|
+
const compileSubscription = (patterns) => {
|
|
11093
|
+
if (!patterns || patterns.length === 0) return () => false;
|
|
11094
|
+
if (patterns.includes("*")) return () => true;
|
|
11095
|
+
const exact = /* @__PURE__ */ new Set();
|
|
11096
|
+
const families = /* @__PURE__ */ new Set();
|
|
11097
|
+
for (const pattern of patterns) {
|
|
11098
|
+
if (pattern.endsWith(".*")) families.add(pattern.slice(0, -2));
|
|
11099
|
+
else exact.add(pattern);
|
|
11100
|
+
}
|
|
11101
|
+
if (families.size === 0) return (name) => exact.has(name);
|
|
11102
|
+
return (name) => {
|
|
11103
|
+
if (exact.has(name)) return true;
|
|
11104
|
+
const dot = name.indexOf(".");
|
|
11105
|
+
return dot > 0 && families.has(name.slice(0, dot));
|
|
11106
|
+
};
|
|
11107
|
+
};
|
|
11108
|
+
const subscriptionKey = (patterns) => patterns ? patterns.join("|") : "";
|
|
11109
|
+
|
|
11110
|
+
const QUEUE_CAP = 200;
|
|
11111
|
+
let handler = null;
|
|
11112
|
+
let matches = () => false;
|
|
11113
|
+
let sessionId = null;
|
|
11114
|
+
let seq = 0;
|
|
11115
|
+
let queue$1 = [];
|
|
11116
|
+
let draining = false;
|
|
11117
|
+
let handlerFailed = false;
|
|
11118
|
+
let registrations = 0;
|
|
11119
|
+
const drain = () => {
|
|
11120
|
+
draining = false;
|
|
11121
|
+
const batch = queue$1;
|
|
11122
|
+
queue$1 = [];
|
|
11123
|
+
const current = handler;
|
|
11124
|
+
if (!current) return;
|
|
11125
|
+
for (const event of batch) {
|
|
11126
|
+
try {
|
|
11127
|
+
current(event);
|
|
11128
|
+
} catch {
|
|
11129
|
+
if (!handlerFailed) {
|
|
11130
|
+
handlerFailed = true;
|
|
11131
|
+
logger.warn(
|
|
11132
|
+
"[SdkEvents] onEvent handler threw; further failures suppressed"
|
|
11133
|
+
);
|
|
11134
|
+
}
|
|
11135
|
+
}
|
|
11136
|
+
}
|
|
11137
|
+
};
|
|
11138
|
+
const schedule = () => {
|
|
11139
|
+
if (draining) return;
|
|
11140
|
+
draining = true;
|
|
11141
|
+
queueMicrotask(drain);
|
|
11142
|
+
};
|
|
11143
|
+
const SdkEventBus = {
|
|
11144
|
+
/**
|
|
11145
|
+
* Installs the host handler. Returns an unsubscribe. Events that matched
|
|
11146
|
+
* the subscription but arrived before a handler existed are queued and
|
|
11147
|
+
* delivered on the next microtask. That window is real: React runs child
|
|
11148
|
+
* effects before parent ones, so a provider below `Omniscribe` can emit
|
|
11149
|
+
* after `setSubscription` and before this call.
|
|
11150
|
+
*/
|
|
11151
|
+
setHandler(next) {
|
|
11152
|
+
registrations += 1;
|
|
11153
|
+
if (next && handler && registrations > 1) {
|
|
11154
|
+
logger.warn(
|
|
11155
|
+
"[SdkEvents] a second onEvent handler was registered. The SDK supports one <Omniscribe> per page; the newest handler wins."
|
|
11156
|
+
);
|
|
11157
|
+
}
|
|
11158
|
+
handler = next;
|
|
11159
|
+
if (next && queue$1.length > 0) schedule();
|
|
11160
|
+
return () => {
|
|
11161
|
+
if (handler === next) handler = null;
|
|
11162
|
+
};
|
|
11163
|
+
},
|
|
11164
|
+
setSubscription(patterns) {
|
|
11165
|
+
matches = compileSubscription(patterns);
|
|
11166
|
+
},
|
|
11167
|
+
setSessionId(next) {
|
|
11168
|
+
sessionId = next;
|
|
11169
|
+
},
|
|
11170
|
+
/**
|
|
11171
|
+
* Cheap guard for callers on a hot path who would otherwise build a
|
|
11172
|
+
* payload for nobody.
|
|
11173
|
+
*/
|
|
11174
|
+
wants(name) {
|
|
11175
|
+
return matches(name);
|
|
11176
|
+
},
|
|
11177
|
+
/**
|
|
11178
|
+
* Queues an event for delivery on the next microtask.
|
|
11179
|
+
*
|
|
11180
|
+
* Never throws. Deferring delivery does three things at once: host code
|
|
11181
|
+
* never runs inside React's render phase (where a `setState` would
|
|
11182
|
+
* throw), a slow handler cannot block `socket.onmessage` on the audio
|
|
11183
|
+
* path, and a handler that itself triggers an event cannot recurse —
|
|
11184
|
+
* the re-entrant call only appends to a queue the current drain has
|
|
11185
|
+
* already taken. One shared drain, not one microtask per event, so `seq`
|
|
11186
|
+
* ordering is preserved.
|
|
11187
|
+
*/
|
|
11188
|
+
emit(name, payload, level = "info") {
|
|
11189
|
+
if (!matches(name)) return;
|
|
11190
|
+
queue$1.push({
|
|
11191
|
+
name,
|
|
11192
|
+
family: familyOf(name),
|
|
11193
|
+
level,
|
|
11194
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11195
|
+
seq: ++seq,
|
|
11196
|
+
sdkVersion: version$2,
|
|
11197
|
+
sessionId,
|
|
11198
|
+
payload
|
|
11199
|
+
});
|
|
11200
|
+
if (queue$1.length > QUEUE_CAP) queue$1.shift();
|
|
11201
|
+
if (handler) schedule();
|
|
11202
|
+
},
|
|
11203
|
+
/** Test-only: restores the module to its initial state. */
|
|
11204
|
+
__resetForTests() {
|
|
11205
|
+
handler = null;
|
|
11206
|
+
matches = () => false;
|
|
11207
|
+
sessionId = null;
|
|
11208
|
+
seq = 0;
|
|
11209
|
+
queue$1 = [];
|
|
11210
|
+
draining = false;
|
|
11211
|
+
handlerFailed = false;
|
|
11212
|
+
registrations = 0;
|
|
11213
|
+
}
|
|
11214
|
+
};
|
|
11215
|
+
|
|
11081
11216
|
const SettingsContext = React__default.createContext(
|
|
11082
11217
|
void 0
|
|
11083
11218
|
);
|
|
@@ -11118,6 +11253,7 @@ const SettingsProvider = ({
|
|
|
11118
11253
|
DEFAULT_MINOR_AGE_THRESHOLD
|
|
11119
11254
|
);
|
|
11120
11255
|
const [isLoading, setIsLoading] = React__default.useState(true);
|
|
11256
|
+
const hasEmittedReadyRef = React__default.useRef(false);
|
|
11121
11257
|
const isInitializedRef = React__default.useRef(false);
|
|
11122
11258
|
const applySettings = React__default.useCallback(
|
|
11123
11259
|
(parsed) => {
|
|
@@ -11170,6 +11306,10 @@ const SettingsProvider = ({
|
|
|
11170
11306
|
SettingsCache.getInstance().clear();
|
|
11171
11307
|
} finally {
|
|
11172
11308
|
setIsLoading(false);
|
|
11309
|
+
if (!hasEmittedReadyRef.current) {
|
|
11310
|
+
hasEmittedReadyRef.current = true;
|
|
11311
|
+
SdkEventBus.emit("lifecycle.ready", {});
|
|
11312
|
+
}
|
|
11173
11313
|
}
|
|
11174
11314
|
}, [toolArgs, templateId, predefinedLanguage, applySettings]);
|
|
11175
11315
|
const reloadSettings = React__default.useCallback(async () => {
|
|
@@ -17282,8 +17422,147 @@ const evaluateMinorRule = ({
|
|
|
17282
17422
|
|
|
17283
17423
|
const postAppEvent = (event) => requester.post("/app-events", event).catch(() => void 0);
|
|
17284
17424
|
|
|
17425
|
+
const ACTIVITY_THROTTLE_MS = 5e3;
|
|
17426
|
+
const lastEmittedAt = /* @__PURE__ */ new Map();
|
|
17427
|
+
const shouldEmit = (key) => {
|
|
17428
|
+
const now = Date.now();
|
|
17429
|
+
const previous = lastEmittedAt.get(key);
|
|
17430
|
+
if (previous !== void 0 && now - previous < ACTIVITY_THROTTLE_MS) {
|
|
17431
|
+
return false;
|
|
17432
|
+
}
|
|
17433
|
+
lastEmittedAt.set(key, now);
|
|
17434
|
+
return true;
|
|
17435
|
+
};
|
|
17436
|
+
const emitInteraction = (kind) => {
|
|
17437
|
+
if (!SdkEventBus.wants("activity.interaction")) return;
|
|
17438
|
+
if (!shouldEmit(`interaction:${kind}`)) return;
|
|
17439
|
+
SdkEventBus.emit("activity.interaction", { kind });
|
|
17440
|
+
};
|
|
17441
|
+
const emitTyping = (surface) => {
|
|
17442
|
+
if (!SdkEventBus.wants("activity.typing")) return;
|
|
17443
|
+
if (!shouldEmit(`typing:${surface}`)) return;
|
|
17444
|
+
SdkEventBus.emit("activity.typing", { surface });
|
|
17445
|
+
};
|
|
17446
|
+
|
|
17447
|
+
let open$1 = false;
|
|
17448
|
+
const openReportBracket = () => {
|
|
17449
|
+
if (open$1) return;
|
|
17450
|
+
open$1 = true;
|
|
17451
|
+
SdkEventBus.emit("report.generation_started", {});
|
|
17452
|
+
};
|
|
17453
|
+
const closeReportBracket = (ok) => {
|
|
17454
|
+
if (!open$1) return;
|
|
17455
|
+
open$1 = false;
|
|
17456
|
+
SdkEventBus.emit("report.settled", { ok });
|
|
17457
|
+
};
|
|
17458
|
+
|
|
17459
|
+
const RECORDING_HEARTBEAT_MS = 3e4;
|
|
17460
|
+
let lastBeatAt = null;
|
|
17461
|
+
const emitRecordingHeartbeat = () => {
|
|
17462
|
+
if (!SdkEventBus.wants("recording.heartbeat")) return;
|
|
17463
|
+
const now = Date.now();
|
|
17464
|
+
if (lastBeatAt !== null && now - lastBeatAt < RECORDING_HEARTBEAT_MS) return;
|
|
17465
|
+
lastBeatAt = now;
|
|
17466
|
+
SdkEventBus.emit("recording.heartbeat", {});
|
|
17467
|
+
};
|
|
17468
|
+
const resetRecordingHeartbeat = () => {
|
|
17469
|
+
lastBeatAt = null;
|
|
17470
|
+
};
|
|
17471
|
+
|
|
17472
|
+
const INTERACTION_KIND = {
|
|
17473
|
+
recording_button: "recording",
|
|
17474
|
+
chat_mic_button: "chat",
|
|
17475
|
+
attach_file_button: "chat",
|
|
17476
|
+
remove_file_button: "chat",
|
|
17477
|
+
edit_message_button: "chat",
|
|
17478
|
+
cancel_edit_message_button: "chat",
|
|
17479
|
+
send_edit_message_button: "chat",
|
|
17480
|
+
copy_human_message_button: "chat",
|
|
17481
|
+
copy_ai_message_button: "chat",
|
|
17482
|
+
settings_button: "settings",
|
|
17483
|
+
settings_back_button: "settings",
|
|
17484
|
+
settings_section_button: "settings",
|
|
17485
|
+
select_audio_environment: "settings",
|
|
17486
|
+
compile_summary_button: "report",
|
|
17487
|
+
regenerate_summary_button: "report",
|
|
17488
|
+
generate_extras_button: "report",
|
|
17489
|
+
expand_transcription_button: "transcript",
|
|
17490
|
+
history_thread_item: "history",
|
|
17491
|
+
close_widget_button: "widget",
|
|
17492
|
+
main_menu_button: "widget",
|
|
17493
|
+
play_panel_button: "widget"
|
|
17494
|
+
};
|
|
17495
|
+
const CLICK_FALLBACK_KIND = "widget";
|
|
17496
|
+
const RECORDING_MODES = ["consultation", "dictation"];
|
|
17497
|
+
const AUDIO_LOSS_CAUSES = ["mic", "network", "server"];
|
|
17498
|
+
const readNumber = (payload, key) => {
|
|
17499
|
+
const value = payload?.[key];
|
|
17500
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
17501
|
+
};
|
|
17502
|
+
const readMode = (payload) => {
|
|
17503
|
+
const value = payload?.mode;
|
|
17504
|
+
return typeof value === "string" && RECORDING_MODES.includes(value) ? value : "consultation";
|
|
17505
|
+
};
|
|
17506
|
+
const readCause = (payload) => {
|
|
17507
|
+
const value = payload?.cause;
|
|
17508
|
+
return typeof value === "string" && AUDIO_LOSS_CAUSES.includes(value) ? value : "server";
|
|
17509
|
+
};
|
|
17510
|
+
const fanOutAppEvent = (input) => {
|
|
17511
|
+
try {
|
|
17512
|
+
const { event_type, event_name, payload } = input;
|
|
17513
|
+
if (event_type === "click") {
|
|
17514
|
+
emitInteraction(INTERACTION_KIND[event_name] ?? CLICK_FALLBACK_KIND);
|
|
17515
|
+
}
|
|
17516
|
+
switch (event_name) {
|
|
17517
|
+
case "recording_started":
|
|
17518
|
+
resetRecordingHeartbeat();
|
|
17519
|
+
SdkEventBus.emit("recording.started", { mode: readMode(payload) });
|
|
17520
|
+
break;
|
|
17521
|
+
case "recording_stopped":
|
|
17522
|
+
SdkEventBus.emit("recording.stopped", {
|
|
17523
|
+
mode: readMode(payload),
|
|
17524
|
+
durationSeconds: readNumber(payload, "duration_seconds")
|
|
17525
|
+
});
|
|
17526
|
+
break;
|
|
17527
|
+
// The mic/network emitter reports the length of the gap once audio
|
|
17528
|
+
// recovers. The server-close emitter has no gap to measure — capture
|
|
17529
|
+
// is torn down on the spot — and reports the recording position
|
|
17530
|
+
// instead, so fall back to that rather than hand the host a silent 0.
|
|
17531
|
+
case "audio_lost":
|
|
17532
|
+
SdkEventBus.emit(
|
|
17533
|
+
"recording.audio_lost",
|
|
17534
|
+
{
|
|
17535
|
+
cause: readCause(payload),
|
|
17536
|
+
durationSeconds: readNumber(payload, "duration_seconds") || readNumber(payload, "recording_position_seconds")
|
|
17537
|
+
},
|
|
17538
|
+
"warn"
|
|
17539
|
+
);
|
|
17540
|
+
break;
|
|
17541
|
+
case "mic_disconnected":
|
|
17542
|
+
SdkEventBus.emit("recording.microphone_disconnected", {}, "warn");
|
|
17543
|
+
break;
|
|
17544
|
+
// A report request is in flight. The host must suppress its idle
|
|
17545
|
+
// timer until report.settled, or it will close the widget during
|
|
17546
|
+
// generation — which looks exactly like idleness and loses the note.
|
|
17547
|
+
// openReportBracket ignores a second click while one is in flight, so
|
|
17548
|
+
// the pair stays balanced.
|
|
17549
|
+
case "compile_summary_button":
|
|
17550
|
+
case "regenerate_summary_button":
|
|
17551
|
+
openReportBracket();
|
|
17552
|
+
break;
|
|
17553
|
+
case "close_widget_button":
|
|
17554
|
+
SdkEventBus.emit("lifecycle.closed", {});
|
|
17555
|
+
break;
|
|
17556
|
+
default:
|
|
17557
|
+
break;
|
|
17558
|
+
}
|
|
17559
|
+
} catch {
|
|
17560
|
+
}
|
|
17561
|
+
};
|
|
17562
|
+
|
|
17285
17563
|
const EventTracker = {
|
|
17286
17564
|
track(input) {
|
|
17565
|
+
fanOutAppEvent(input);
|
|
17287
17566
|
const event = {
|
|
17288
17567
|
event_type: input.event_type,
|
|
17289
17568
|
event_name: input.event_name,
|
|
@@ -21051,6 +21330,7 @@ const useAudioProcessor = ({
|
|
|
21051
21330
|
);
|
|
21052
21331
|
socket.send(audioData16kHz);
|
|
21053
21332
|
lastSendAtRef.current = Date.now();
|
|
21333
|
+
emitRecordingHeartbeat();
|
|
21054
21334
|
}
|
|
21055
21335
|
};
|
|
21056
21336
|
audioTracks.forEach((t) => {
|
|
@@ -22540,6 +22820,7 @@ const useReportPreviewState = ({
|
|
|
22540
22820
|
}, []);
|
|
22541
22821
|
const setScalarEdit = React__default.useCallback(
|
|
22542
22822
|
(entryKey, value) => {
|
|
22823
|
+
emitTyping("note");
|
|
22543
22824
|
setEdits((prev) => {
|
|
22544
22825
|
const next = new Map(prev);
|
|
22545
22826
|
next.set(entryKey, value);
|
|
@@ -22550,6 +22831,7 @@ const useReportPreviewState = ({
|
|
|
22550
22831
|
);
|
|
22551
22832
|
const setRowFieldEdit = React__default.useCallback(
|
|
22552
22833
|
(entryKey, rowIndex, fieldKey, value) => {
|
|
22834
|
+
emitTyping("note");
|
|
22553
22835
|
setEdits((prev) => {
|
|
22554
22836
|
const next = new Map(prev);
|
|
22555
22837
|
next.set(rowFieldEditKey(entryKey, rowIndex, fieldKey), value);
|
|
@@ -22559,6 +22841,7 @@ const useReportPreviewState = ({
|
|
|
22559
22841
|
[]
|
|
22560
22842
|
);
|
|
22561
22843
|
const setScalarGapValue = React__default.useCallback((key, value) => {
|
|
22844
|
+
emitTyping("note");
|
|
22562
22845
|
setFilledScalarGaps((prev) => {
|
|
22563
22846
|
const next = new Map(prev);
|
|
22564
22847
|
next.set(key, value);
|
|
@@ -24458,6 +24741,7 @@ const useReportGeneration = (options) => {
|
|
|
24458
24741
|
} finally {
|
|
24459
24742
|
setState((prev) => ({ ...prev, generating: false }));
|
|
24460
24743
|
regenerateInflightRef.current = false;
|
|
24744
|
+
closeReportBracket(false);
|
|
24461
24745
|
}
|
|
24462
24746
|
}, [
|
|
24463
24747
|
abortIfBlocked,
|
|
@@ -24498,6 +24782,7 @@ const useReportGeneration = (options) => {
|
|
|
24498
24782
|
handleReport?.(result);
|
|
24499
24783
|
}
|
|
24500
24784
|
trackEvent("event", "summary_compiled");
|
|
24785
|
+
closeReportBracket(true);
|
|
24501
24786
|
if (patientId && doctorId) {
|
|
24502
24787
|
await saveDayData({
|
|
24503
24788
|
patientId,
|
|
@@ -24688,6 +24973,7 @@ const useReportGeneration = (options) => {
|
|
|
24688
24973
|
}
|
|
24689
24974
|
} finally {
|
|
24690
24975
|
generateInflightRef.current = false;
|
|
24976
|
+
closeReportBracket(false);
|
|
24691
24977
|
setUserPendingClick(false);
|
|
24692
24978
|
const finalPid = appointmentData?.patientId;
|
|
24693
24979
|
const finalDid = appointmentData?.doctorId;
|
|
@@ -151315,122 +151601,108 @@ const ChatFooter = ({
|
|
|
151315
151601
|
]
|
|
151316
151602
|
}
|
|
151317
151603
|
),
|
|
151318
|
-
/* @__PURE__ */ jsxs(
|
|
151319
|
-
|
|
151320
|
-
|
|
151321
|
-
|
|
151322
|
-
|
|
151323
|
-
|
|
151324
|
-
|
|
151325
|
-
|
|
151326
|
-
|
|
151327
|
-
|
|
151328
|
-
|
|
151329
|
-
|
|
151330
|
-
|
|
151331
|
-
|
|
151332
|
-
|
|
151333
|
-
|
|
151334
|
-
|
|
151335
|
-
|
|
151336
|
-
"div",
|
|
151337
|
-
|
|
151338
|
-
|
|
151339
|
-
|
|
151340
|
-
|
|
151341
|
-
|
|
151342
|
-
/* @__PURE__ */ jsx$2(
|
|
151343
|
-
|
|
151604
|
+
/* @__PURE__ */ jsxs("div", { className: "omniscribe_chat-view-combined-footer-row", children: [
|
|
151605
|
+
/* @__PURE__ */ jsx$2(
|
|
151606
|
+
"input",
|
|
151607
|
+
{
|
|
151608
|
+
ref: fileInputRef,
|
|
151609
|
+
type: "file",
|
|
151610
|
+
multiple: true,
|
|
151611
|
+
accept: "image/*,.pdf",
|
|
151612
|
+
onChange: onFileSelect,
|
|
151613
|
+
style: { display: "none" }
|
|
151614
|
+
}
|
|
151615
|
+
),
|
|
151616
|
+
/* @__PURE__ */ jsxs(
|
|
151617
|
+
"div",
|
|
151618
|
+
{
|
|
151619
|
+
className: `omniscribe_chat-view-combined-input-container${uploadedFiles.length > 0 ? " omniscribe_chat-view-combined-input-container--with-files" : ""}`,
|
|
151620
|
+
children: [
|
|
151621
|
+
uploadedFiles.length > 0 && /* @__PURE__ */ jsx$2("div", { className: "omniscribe_chat-view-combined-files-row", children: /* @__PURE__ */ jsx$2(FilePreview, { files: uploadedFiles, onRemove: onFileRemove }) }),
|
|
151622
|
+
/* @__PURE__ */ jsxs("div", { className: "omniscribe_chat-view-combined-input-row", children: [
|
|
151623
|
+
/* @__PURE__ */ jsx$2(
|
|
151624
|
+
Tooltip,
|
|
151625
|
+
{
|
|
151626
|
+
message: formatMessage({ id: "Attach file" }),
|
|
151627
|
+
side: "top",
|
|
151628
|
+
children: /* @__PURE__ */ jsx$2(
|
|
151629
|
+
"button",
|
|
151344
151630
|
{
|
|
151345
|
-
|
|
151346
|
-
|
|
151631
|
+
type: "button",
|
|
151632
|
+
className: "omniscribe_chat-view-combined-clip-icon",
|
|
151633
|
+
onClick: () => {
|
|
151634
|
+
trackEvent("click", "attach_file_button");
|
|
151635
|
+
onAttachClick();
|
|
151636
|
+
},
|
|
151637
|
+
disabled: uploadedFiles.length >= MAX_FILES,
|
|
151638
|
+
"aria-label": formatMessage({ id: "Attach file" }),
|
|
151347
151639
|
children: /* @__PURE__ */ jsx$2(
|
|
151348
|
-
"
|
|
151640
|
+
"svg",
|
|
151349
151641
|
{
|
|
151350
|
-
|
|
151351
|
-
|
|
151352
|
-
|
|
151353
|
-
|
|
151354
|
-
|
|
151355
|
-
|
|
151356
|
-
|
|
151357
|
-
|
|
151358
|
-
children: /* @__PURE__ */ jsx$2(
|
|
151359
|
-
"svg",
|
|
151360
|
-
{
|
|
151361
|
-
width: "12",
|
|
151362
|
-
height: "12",
|
|
151363
|
-
viewBox: "0 0 24 24",
|
|
151364
|
-
fill: "none",
|
|
151365
|
-
stroke: "currentColor",
|
|
151366
|
-
strokeWidth: "2",
|
|
151367
|
-
strokeLinecap: "round",
|
|
151368
|
-
strokeLinejoin: "round",
|
|
151369
|
-
children: /* @__PURE__ */ jsx$2("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" })
|
|
151370
|
-
}
|
|
151371
|
-
)
|
|
151642
|
+
width: "12",
|
|
151643
|
+
height: "12",
|
|
151644
|
+
viewBox: "0 0 24 24",
|
|
151645
|
+
fill: "none",
|
|
151646
|
+
stroke: "currentColor",
|
|
151647
|
+
strokeWidth: "2",
|
|
151648
|
+
strokeLinecap: "round",
|
|
151649
|
+
strokeLinejoin: "round",
|
|
151650
|
+
children: /* @__PURE__ */ jsx$2("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" })
|
|
151372
151651
|
}
|
|
151373
151652
|
)
|
|
151374
151653
|
}
|
|
151375
|
-
)
|
|
151376
|
-
|
|
151377
|
-
|
|
151378
|
-
|
|
151379
|
-
|
|
151380
|
-
|
|
151381
|
-
|
|
151382
|
-
|
|
151383
|
-
|
|
151384
|
-
|
|
151385
|
-
|
|
151386
|
-
|
|
151387
|
-
|
|
151388
|
-
|
|
151389
|
-
|
|
151390
|
-
|
|
151391
|
-
}
|
|
151392
|
-
},
|
|
151393
|
-
maxLength: inputMaxLength,
|
|
151394
|
-
className: "omniscribe_chat-view-combined-textarea no-scrollbar text-p",
|
|
151395
|
-
placeholder: formatMessage({
|
|
151396
|
-
id: "What do you need to know?"
|
|
151397
|
-
})
|
|
151398
|
-
}
|
|
151399
|
-
),
|
|
151400
|
-
isLoading ? /* @__PURE__ */ jsx$2(
|
|
151401
|
-
"button",
|
|
151402
|
-
{
|
|
151403
|
-
type: "button",
|
|
151404
|
-
"data-testid": "sofia-chat-stop",
|
|
151405
|
-
onClick: onStop,
|
|
151406
|
-
className: "omniscribe_chat-view-combined-send-btn omniscribe_chat-view-combined-stop-btn",
|
|
151407
|
-
title: formatMessage({ id: "Stop" }),
|
|
151408
|
-
children: /* @__PURE__ */ jsx$2(SquareIcon, { width: 10, height: 10 })
|
|
151409
|
-
}
|
|
151410
|
-
) : inputValue.length > 0 ? /* @__PURE__ */ jsx$2(
|
|
151411
|
-
"button",
|
|
151412
|
-
{
|
|
151413
|
-
type: "button",
|
|
151414
|
-
"data-testid": "sofia-chat-send",
|
|
151415
|
-
onClick: (e) => {
|
|
151416
|
-
const form = e.currentTarget.closest(
|
|
151417
|
-
"form"
|
|
151418
|
-
);
|
|
151419
|
-
form?.requestSubmit();
|
|
151420
|
-
},
|
|
151421
|
-
className: "omniscribe_chat-view-combined-send-btn",
|
|
151422
|
-
disabled: isLoading || !inputIsValid,
|
|
151423
|
-
title: formatMessage({ id: "Send" }),
|
|
151424
|
-
children: /* @__PURE__ */ jsx$2(SendArrowIcon, { width: 16, height: 16 })
|
|
151654
|
+
)
|
|
151655
|
+
}
|
|
151656
|
+
),
|
|
151657
|
+
/* @__PURE__ */ jsx$2(
|
|
151658
|
+
Textarea,
|
|
151659
|
+
{
|
|
151660
|
+
ref: textareaRef,
|
|
151661
|
+
rows: 1,
|
|
151662
|
+
"data-testid": "sofia-chat-input",
|
|
151663
|
+
value: inputValue,
|
|
151664
|
+
variant: "secondary",
|
|
151665
|
+
onChange: onInputChange,
|
|
151666
|
+
onKeyDown: (e) => {
|
|
151667
|
+
if (e.key === "Enter" && !e.shiftKey && !e.metaKey) {
|
|
151668
|
+
e.preventDefault();
|
|
151669
|
+
onSubmit(e);
|
|
151425
151670
|
}
|
|
151426
|
-
|
|
151427
|
-
|
|
151428
|
-
|
|
151429
|
-
|
|
151430
|
-
|
|
151431
|
-
|
|
151432
|
-
|
|
151433
|
-
|
|
151671
|
+
},
|
|
151672
|
+
maxLength: inputMaxLength,
|
|
151673
|
+
className: "omniscribe_chat-view-combined-textarea no-scrollbar text-p",
|
|
151674
|
+
placeholder: formatMessage({
|
|
151675
|
+
id: "What do you need to know?"
|
|
151676
|
+
})
|
|
151677
|
+
}
|
|
151678
|
+
),
|
|
151679
|
+
isLoading ? /* @__PURE__ */ jsx$2(
|
|
151680
|
+
"button",
|
|
151681
|
+
{
|
|
151682
|
+
type: "button",
|
|
151683
|
+
"data-testid": "sofia-chat-stop",
|
|
151684
|
+
onClick: onStop,
|
|
151685
|
+
className: "omniscribe_chat-view-combined-send-btn omniscribe_chat-view-combined-stop-btn",
|
|
151686
|
+
title: formatMessage({ id: "Stop" }),
|
|
151687
|
+
children: /* @__PURE__ */ jsx$2(SquareIcon, { width: 10, height: 10 })
|
|
151688
|
+
}
|
|
151689
|
+
) : inputValue.length > 0 ? /* @__PURE__ */ jsx$2(
|
|
151690
|
+
"button",
|
|
151691
|
+
{
|
|
151692
|
+
type: "button",
|
|
151693
|
+
"data-testid": "sofia-chat-send",
|
|
151694
|
+
onClick: onSubmit,
|
|
151695
|
+
className: "omniscribe_chat-view-combined-send-btn",
|
|
151696
|
+
disabled: isLoading || !inputIsValid,
|
|
151697
|
+
title: formatMessage({ id: "Send" }),
|
|
151698
|
+
children: /* @__PURE__ */ jsx$2(SendArrowIcon, { width: 16, height: 16 })
|
|
151699
|
+
}
|
|
151700
|
+
) : /* @__PURE__ */ jsx$2(MicrophoneButton, { onTextUpdate: onTranscriptionUpdate })
|
|
151701
|
+
] })
|
|
151702
|
+
]
|
|
151703
|
+
}
|
|
151704
|
+
)
|
|
151705
|
+
] })
|
|
151434
151706
|
] })
|
|
151435
151707
|
] });
|
|
151436
151708
|
};
|
|
@@ -152083,6 +152355,7 @@ const ChatView = () => {
|
|
|
152083
152355
|
appointmentData?.doctorId
|
|
152084
152356
|
]);
|
|
152085
152357
|
const handleInputChange = (e) => {
|
|
152358
|
+
emitTyping("chat");
|
|
152086
152359
|
input.onChange(e);
|
|
152087
152360
|
setInputIsValid(
|
|
152088
152361
|
InputValidator.validate(e.target.value, CHAT_INPUT_VALIDATION).isValid
|
|
@@ -156492,6 +156765,9 @@ const SessionProvider = ({ children }) => {
|
|
|
156492
156765
|
prevPatientIdRef.current = patientId;
|
|
156493
156766
|
setSessionId(patientId ? generateUuid() : null);
|
|
156494
156767
|
}, [patientId]);
|
|
156768
|
+
useEffect(() => {
|
|
156769
|
+
SdkEventBus.setSessionId(sessionId);
|
|
156770
|
+
}, [sessionId]);
|
|
156495
156771
|
return /* @__PURE__ */ jsx$2(SessionContext.Provider, { value: { sessionId }, children });
|
|
156496
156772
|
};
|
|
156497
156773
|
|
|
@@ -156711,7 +156987,9 @@ const Omniscribe = ({
|
|
|
156711
156987
|
onReportApply,
|
|
156712
156988
|
updateTemplate,
|
|
156713
156989
|
templateExtras,
|
|
156714
|
-
handleExtras
|
|
156990
|
+
handleExtras,
|
|
156991
|
+
onEvent,
|
|
156992
|
+
eventSubscriptions
|
|
156715
156993
|
}) => {
|
|
156716
156994
|
const templateFields = template ?? toolsargs;
|
|
156717
156995
|
const effectiveBaseUrl = React.useMemo(
|
|
@@ -156760,6 +157038,28 @@ const Omniscribe = ({
|
|
|
156760
157038
|
React.useEffect(() => {
|
|
156761
157039
|
logger.setDebugMode(debug || false);
|
|
156762
157040
|
}, [debug]);
|
|
157041
|
+
const onEventRef = React.useRef(onEvent);
|
|
157042
|
+
onEventRef.current = onEvent;
|
|
157043
|
+
const hasEventHandler = onEvent !== void 0;
|
|
157044
|
+
const subscriptionsRef = React.useRef(
|
|
157045
|
+
eventSubscriptions
|
|
157046
|
+
);
|
|
157047
|
+
subscriptionsRef.current = eventSubscriptions;
|
|
157048
|
+
const subscriptions = subscriptionKey(eventSubscriptions);
|
|
157049
|
+
React.useEffect(() => {
|
|
157050
|
+
SdkEventBus.setSubscription(subscriptionsRef.current);
|
|
157051
|
+
}, [subscriptions]);
|
|
157052
|
+
React.useEffect(() => {
|
|
157053
|
+
if (!hasEventHandler) return;
|
|
157054
|
+
return SdkEventBus.setHandler((event) => onEventRef.current?.(event));
|
|
157055
|
+
}, [hasEventHandler]);
|
|
157056
|
+
React.useEffect(() => {
|
|
157057
|
+
if (hasEventHandler && !eventSubscriptions?.length) {
|
|
157058
|
+
logger.warn(
|
|
157059
|
+
'[Sofia SDK] onEvent was provided without eventSubscriptions, so no events will be delivered. Pass e.g. ["recording.*", "activity.*"].'
|
|
157060
|
+
);
|
|
157061
|
+
}
|
|
157062
|
+
}, [hasEventHandler, eventSubscriptions]);
|
|
156763
157063
|
React.useEffect(() => {
|
|
156764
157064
|
if (apikey && apikey.trim() !== "") {
|
|
156765
157065
|
setEncryptionSeed(apikey);
|