@fayz-ai/plugin-scribe 0.11.2 → 0.12.0
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/components/ScribeAssistantBridge.d.ts +5 -3
- package/dist/components/ScribeAssistantBridge.d.ts.map +1 -1
- package/dist/components/ScribeHeaderAction.d.ts.map +1 -1
- package/dist/components/ScribeRecordingPill.d.ts +1 -1
- package/dist/components/ScribeRecordingPill.d.ts.map +1 -1
- package/dist/components/ScribeSessionPage.d.ts +5 -2
- package/dist/components/ScribeSessionPage.d.ts.map +1 -1
- package/dist/components/ScribeShellMount.d.ts +3 -10
- package/dist/components/ScribeShellMount.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +217 -306
- package/dist/index.js.map +1 -1
- package/dist/lib/start.d.ts +47 -0
- package/dist/lib/start.d.ts.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/dist/components/ScribeConsentDialog.d.ts +0 -12
- package/dist/components/ScribeConsentDialog.d.ts.map +0 -1
- package/dist/components/ScribeRecoveryBanner.d.ts +0 -8
- package/dist/components/ScribeRecoveryBanner.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import
|
|
1
|
+
import * as React5 from 'react';
|
|
2
|
+
import React5__default from 'react';
|
|
3
3
|
import { getActiveTenantId, getSupabaseClientOptional, registerTranslations } from '@fayz-ai/core';
|
|
4
4
|
import { create } from 'zustand';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
|
-
import {
|
|
6
|
+
import { Mic, FileText, Sparkles, Loader2, Pause, Play, Square, Settings2, AlertTriangle, RefreshCw, Trash2, Check } from 'lucide-react';
|
|
7
7
|
import { Button, toast, Skeleton, Badge, Tabs, TabsList, TabsTrigger, TabsContent, Card, CardContent, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, Checkbox, ModalFooter, MarkdownEditor } from '@fayz-ai/ui/primitives';
|
|
8
|
-
import { Mic, FileText, Sparkles, Loader2, Pause, Play, Square, Settings2, AlertTriangle, RefreshCw, Trash2, Check, ShieldCheck } from 'lucide-react';
|
|
9
8
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
9
|
+
import { openAssistantAs, useAgentSurface, registerTimelineSource, useAccessOptional, useAuth, usePublishAssistantActivity, useRegisterAssistantLauncher, resolveFayzAgentConnection } from '@fayz-ai/admin';
|
|
10
10
|
import { SubpageHeader } from '@fayz-ai/ui/layout';
|
|
11
11
|
|
|
12
12
|
// src/index.ts
|
|
@@ -1083,10 +1083,10 @@ function formatElapsed(ms) {
|
|
|
1083
1083
|
}
|
|
1084
1084
|
var MOBILE_BREAKPOINT = 768;
|
|
1085
1085
|
function useIsMobile() {
|
|
1086
|
-
const [isMobile, setIsMobile] =
|
|
1086
|
+
const [isMobile, setIsMobile] = React5.useState(
|
|
1087
1087
|
() => typeof window !== "undefined" && window.innerWidth < MOBILE_BREAKPOINT
|
|
1088
1088
|
);
|
|
1089
|
-
|
|
1089
|
+
React5.useEffect(() => {
|
|
1090
1090
|
const mq = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
1091
1091
|
const onChange = (e) => setIsMobile(e.matches);
|
|
1092
1092
|
setIsMobile(mq.matches);
|
|
@@ -1096,8 +1096,8 @@ function useIsMobile() {
|
|
|
1096
1096
|
return isMobile;
|
|
1097
1097
|
}
|
|
1098
1098
|
function useTicker(active) {
|
|
1099
|
-
const [, force] =
|
|
1100
|
-
|
|
1099
|
+
const [, force] = React5.useReducer((n) => n + 1, 0);
|
|
1100
|
+
React5.useEffect(() => {
|
|
1101
1101
|
if (!active) return;
|
|
1102
1102
|
let raf = 0;
|
|
1103
1103
|
let last = 0;
|
|
@@ -1121,13 +1121,14 @@ function useTicker(active) {
|
|
|
1121
1121
|
function ScribeRecordingPill({ labels, onOpenSession, mobileOnly }) {
|
|
1122
1122
|
const state = useScribeStore((s) => s.state);
|
|
1123
1123
|
const sessionId = useScribeStore((s) => s.sessionId);
|
|
1124
|
+
const subjectId = useScribeStore((s) => s.subjectId);
|
|
1124
1125
|
const subjectName = useScribeStore((s) => s.subjectName);
|
|
1125
1126
|
const isMobile = useIsMobile();
|
|
1126
|
-
const [busy, setBusy] =
|
|
1127
|
+
const [busy, setBusy] = React5.useState(false);
|
|
1127
1128
|
const active = state === "recording" || state === "paused" || state === "interrupted";
|
|
1128
1129
|
useTicker(state === "recording");
|
|
1129
1130
|
const elapsedMs2 = active ? getSnapshot().elapsedMs : 0;
|
|
1130
|
-
const handleToggle =
|
|
1131
|
+
const handleToggle = React5.useCallback(async () => {
|
|
1131
1132
|
setBusy(true);
|
|
1132
1133
|
try {
|
|
1133
1134
|
if (state === "recording") await pauseSession();
|
|
@@ -1136,15 +1137,15 @@ function ScribeRecordingPill({ labels, onOpenSession, mobileOnly }) {
|
|
|
1136
1137
|
setBusy(false);
|
|
1137
1138
|
}
|
|
1138
1139
|
}, [state]);
|
|
1139
|
-
const handleStop =
|
|
1140
|
+
const handleStop = React5.useCallback(async () => {
|
|
1140
1141
|
setBusy(true);
|
|
1141
1142
|
try {
|
|
1142
1143
|
const id = await endSession();
|
|
1143
|
-
if (id) onOpenSession?.(id);
|
|
1144
|
+
if (id) onOpenSession?.(id, subjectId);
|
|
1144
1145
|
} finally {
|
|
1145
1146
|
setBusy(false);
|
|
1146
1147
|
}
|
|
1147
|
-
}, [onOpenSession]);
|
|
1148
|
+
}, [onOpenSession, subjectId]);
|
|
1148
1149
|
if (!active || !sessionId) return null;
|
|
1149
1150
|
if (mobileOnly && !isMobile) return null;
|
|
1150
1151
|
const tone = state === "recording" ? "bg-destructive/10 text-destructive border-destructive/30" : state === "interrupted" ? "bg-amber-500/10 text-amber-700 border-amber-500/30 dark:text-amber-400" : "bg-muted text-muted-foreground border-border";
|
|
@@ -1160,7 +1161,7 @@ function ScribeRecordingPill({ labels, onOpenSession, mobileOnly }) {
|
|
|
1160
1161
|
"button",
|
|
1161
1162
|
{
|
|
1162
1163
|
type: "button",
|
|
1163
|
-
onClick: () => onOpenSession?.(sessionId),
|
|
1164
|
+
onClick: () => onOpenSession?.(sessionId, subjectId),
|
|
1164
1165
|
className: "flex items-center gap-1.5 text-sm font-medium tabular-nums",
|
|
1165
1166
|
title: subjectName ?? labels.sessionSingular,
|
|
1166
1167
|
children: [
|
|
@@ -1221,112 +1222,6 @@ function ScribeStartButton({ labels, disabled, onStart, variant = "default", siz
|
|
|
1221
1222
|
labels.start
|
|
1222
1223
|
] });
|
|
1223
1224
|
}
|
|
1224
|
-
var RESUMABLE_WINDOW_MS = 30 * 60 * 1e3;
|
|
1225
|
-
function ScribeRecoveryBanner({ labels, onOpenSession }) {
|
|
1226
|
-
const orphans2 = useScribeStore((s) => s.orphans);
|
|
1227
|
-
const state = useScribeStore((s) => s.state);
|
|
1228
|
-
const [busy, setBusy] = React7.useState(null);
|
|
1229
|
-
const live2 = state === "recording" || state === "paused" || state === "requesting";
|
|
1230
|
-
if (live2) return null;
|
|
1231
|
-
if (orphans2.length === 0) return null;
|
|
1232
|
-
const session = orphans2[0];
|
|
1233
|
-
const interruptedAgoMs = Date.now() - session.lastTickEpochMs;
|
|
1234
|
-
const canResume = interruptedAgoMs < RESUMABLE_WINDOW_MS;
|
|
1235
|
-
const durationLabel = formatElapsed(orphanDurationMs(session));
|
|
1236
|
-
const run = async (fn) => {
|
|
1237
|
-
setBusy(session.id);
|
|
1238
|
-
try {
|
|
1239
|
-
await fn();
|
|
1240
|
-
} finally {
|
|
1241
|
-
setBusy(null);
|
|
1242
|
-
}
|
|
1243
|
-
};
|
|
1244
|
-
return /* @__PURE__ */ jsxs("div", { className: "mx-3 mb-3 flex flex-col gap-2 rounded-lg border border-amber-500/40 bg-amber-500/10 p-3 md:mx-6 md:flex-row md:items-center md:justify-between", children: [
|
|
1245
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
1246
|
-
/* @__PURE__ */ jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600 dark:text-amber-400" }),
|
|
1247
|
-
/* @__PURE__ */ jsxs("div", { className: "text-sm", children: [
|
|
1248
|
-
/* @__PURE__ */ jsxs("p", { className: "font-medium", children: [
|
|
1249
|
-
labels.sessionSingular,
|
|
1250
|
-
" de ",
|
|
1251
|
-
durationLabel,
|
|
1252
|
-
" foi interrompido",
|
|
1253
|
-
session.subjectName ? ` \u2014 ${session.subjectName}` : "",
|
|
1254
|
-
"."
|
|
1255
|
-
] }),
|
|
1256
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "O \xE1udio j\xE1 gravado est\xE1 seguro e continua sendo enviado." })
|
|
1257
|
-
] })
|
|
1258
|
-
] }),
|
|
1259
|
-
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-wrap gap-1.5", children: [
|
|
1260
|
-
canResume && /* @__PURE__ */ jsx(Button, { size: "sm", disabled: busy === session.id, onClick: () => void run(resumeSession), children: labels.resume }),
|
|
1261
|
-
/* @__PURE__ */ jsx(
|
|
1262
|
-
Button,
|
|
1263
|
-
{
|
|
1264
|
-
size: "sm",
|
|
1265
|
-
variant: "outline",
|
|
1266
|
-
disabled: busy === session.id,
|
|
1267
|
-
onClick: () => void run(async () => {
|
|
1268
|
-
const id = await endSession();
|
|
1269
|
-
dismissOrphan(session.id);
|
|
1270
|
-
if (id) onOpenSession?.(id);
|
|
1271
|
-
}),
|
|
1272
|
-
children: labels.finish
|
|
1273
|
-
}
|
|
1274
|
-
),
|
|
1275
|
-
/* @__PURE__ */ jsx(
|
|
1276
|
-
Button,
|
|
1277
|
-
{
|
|
1278
|
-
size: "sm",
|
|
1279
|
-
variant: "ghost",
|
|
1280
|
-
disabled: busy === session.id,
|
|
1281
|
-
onClick: () => void run(() => discardSession(session.id)),
|
|
1282
|
-
children: labels.discard
|
|
1283
|
-
}
|
|
1284
|
-
)
|
|
1285
|
-
] })
|
|
1286
|
-
] });
|
|
1287
|
-
}
|
|
1288
|
-
function ScribeConsentDialog({
|
|
1289
|
-
open,
|
|
1290
|
-
labels,
|
|
1291
|
-
subjectName,
|
|
1292
|
-
defaultConsentMode,
|
|
1293
|
-
onCancel,
|
|
1294
|
-
onConfirm
|
|
1295
|
-
}) {
|
|
1296
|
-
const [acknowledged, setAcknowledged] = React7.useState(false);
|
|
1297
|
-
React7.useEffect(() => {
|
|
1298
|
-
if (open) setAcknowledged(false);
|
|
1299
|
-
}, [open]);
|
|
1300
|
-
return /* @__PURE__ */ jsx(Modal, { open, onOpenChange: (next) => !next && onCancel(), children: /* @__PURE__ */ jsxs(ModalContent, { size: "sm", children: [
|
|
1301
|
-
/* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsxs(ModalTitle, { className: "flex items-center gap-2", children: [
|
|
1302
|
-
/* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" }),
|
|
1303
|
-
"Iniciar grava\xE7\xE3o"
|
|
1304
|
-
] }) }),
|
|
1305
|
-
/* @__PURE__ */ jsxs(ModalBody, { className: "space-y-3 text-sm", children: [
|
|
1306
|
-
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground", children: [
|
|
1307
|
-
"O \xE1udio ",
|
|
1308
|
-
subjectName ? `de ${subjectName}` : `deste ${labels.sessionSingular.toLowerCase()}`,
|
|
1309
|
-
" ser\xE1 gravado e transcrito para gerar um documento. A grava\xE7\xE3o fica vis\xEDvel na barra superior enquanto durar."
|
|
1310
|
-
] }),
|
|
1311
|
-
/* @__PURE__ */ jsxs("label", { className: "flex cursor-pointer items-start gap-2 rounded-md border p-3", children: [
|
|
1312
|
-
/* @__PURE__ */ jsx(Checkbox, { checked: acknowledged, onChange: setAcknowledged, className: "mt-0.5" }),
|
|
1313
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
1314
|
-
"Informei ",
|
|
1315
|
-
subjectName ?? "o titular",
|
|
1316
|
-
" de que este atendimento ser\xE1 gravado e obtive o consentimento."
|
|
1317
|
-
] })
|
|
1318
|
-
] }),
|
|
1319
|
-
/* @__PURE__ */ jsxs("p", { className: "flex items-start gap-2 text-xs text-muted-foreground", children: [
|
|
1320
|
-
/* @__PURE__ */ jsx(ShieldCheck, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
|
|
1321
|
-
"O \xE1udio \xE9 armazenado de forma privada e pode ser apagado a qualquer momento \u2014 a transcri\xE7\xE3o e o documento assinado permanecem."
|
|
1322
|
-
] })
|
|
1323
|
-
] }),
|
|
1324
|
-
/* @__PURE__ */ jsxs(ModalFooter, { children: [
|
|
1325
|
-
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onCancel, children: "Cancelar" }),
|
|
1326
|
-
/* @__PURE__ */ jsx(Button, { size: "sm", disabled: !acknowledged, onClick: () => onConfirm(defaultConsentMode), children: labels.start })
|
|
1327
|
-
] })
|
|
1328
|
-
] }) });
|
|
1329
|
-
}
|
|
1330
1225
|
function client() {
|
|
1331
1226
|
const supabase = getSupabaseClientOptional();
|
|
1332
1227
|
if (!supabase) throw new Error("Supabase n\xE3o inicializado");
|
|
@@ -1866,11 +1761,24 @@ function watchTranscript(sessionId, stt) {
|
|
|
1866
1761
|
function transcriptText() {
|
|
1867
1762
|
return useLiveTranscript.getState().segments.map((s) => s.gap ? "[trecho perdido]" : (s.text ?? "").trim()).filter(Boolean).join(" ");
|
|
1868
1763
|
}
|
|
1764
|
+
var SCRIBE_START_EVENT = "scribe:start";
|
|
1765
|
+
var SCRIBE_AGENT_ROLE = "encounter";
|
|
1766
|
+
function requestScribeStart(detail) {
|
|
1767
|
+
window.dispatchEvent(new CustomEvent(SCRIBE_START_EVENT, { detail }));
|
|
1768
|
+
}
|
|
1769
|
+
function scribeSessionPath(args) {
|
|
1770
|
+
const { sessionId, subjectId, subjectEntity } = args;
|
|
1771
|
+
return subjectId ? `/${subjectEntity}/${subjectId}/scribe/${sessionId}` : `/scribe/${sessionId}`;
|
|
1772
|
+
}
|
|
1773
|
+
function startScribeSession(detail = {}) {
|
|
1774
|
+
if (!openAssistantAs(SCRIBE_AGENT_ROLE)) return;
|
|
1775
|
+
requestScribeStart(detail);
|
|
1776
|
+
}
|
|
1869
1777
|
|
|
1870
1778
|
// src/components/ScribeAssistantBridge.tsx
|
|
1871
1779
|
function useSecondTicker(active) {
|
|
1872
|
-
const [, force] =
|
|
1873
|
-
|
|
1780
|
+
const [, force] = React5.useReducer((n) => n + 1, 0);
|
|
1781
|
+
React5.useEffect(() => {
|
|
1874
1782
|
if (!active) return;
|
|
1875
1783
|
const timer3 = setInterval(() => {
|
|
1876
1784
|
if (document.visibilityState === "visible") force();
|
|
@@ -1883,18 +1791,83 @@ function useSecondTicker(active) {
|
|
|
1883
1791
|
};
|
|
1884
1792
|
}, [active]);
|
|
1885
1793
|
}
|
|
1886
|
-
|
|
1794
|
+
var RESUMABLE_WINDOW_MS = 30 * 60 * 1e3;
|
|
1795
|
+
function ScribeAssistantBridge({
|
|
1796
|
+
labels,
|
|
1797
|
+
retention: retention2,
|
|
1798
|
+
stt,
|
|
1799
|
+
locale,
|
|
1800
|
+
onOpenSession
|
|
1801
|
+
}) {
|
|
1802
|
+
const { user } = useAuth();
|
|
1887
1803
|
const state = useScribeStore((s) => s.state);
|
|
1888
1804
|
const sessionId = useScribeStore((s) => s.sessionId);
|
|
1805
|
+
const subjectId = useScribeStore((s) => s.subjectId);
|
|
1889
1806
|
const subjectName = useScribeStore((s) => s.subjectName);
|
|
1807
|
+
const orphans2 = useScribeStore((s) => s.orphans);
|
|
1890
1808
|
const live2 = state === "recording" || state === "paused" || state === "interrupted";
|
|
1891
1809
|
useSecondTicker(state === "recording");
|
|
1892
|
-
|
|
1810
|
+
React5.useEffect(() => {
|
|
1893
1811
|
watchTranscript(live2 ? sessionId : null, stt);
|
|
1894
1812
|
}, [live2, sessionId, stt]);
|
|
1895
1813
|
const elapsedMs2 = live2 ? Math.floor(getSnapshot().elapsedMs / 1e3) * 1e3 : 0;
|
|
1896
|
-
const [
|
|
1897
|
-
const
|
|
1814
|
+
const [pending, setPending] = React5.useState(null);
|
|
1815
|
+
const start = React5.useCallback(
|
|
1816
|
+
async (detail, consentMode) => {
|
|
1817
|
+
setPending(null);
|
|
1818
|
+
if (!user?.id) {
|
|
1819
|
+
toast.error("Fa\xE7a login para gravar um atendimento");
|
|
1820
|
+
return;
|
|
1821
|
+
}
|
|
1822
|
+
const result = await beginSession({
|
|
1823
|
+
userId: user.id,
|
|
1824
|
+
subjectId: detail.subjectId,
|
|
1825
|
+
subjectName: detail.subjectName,
|
|
1826
|
+
appointmentId: detail.appointmentId,
|
|
1827
|
+
templateKeys: detail.templateKeys,
|
|
1828
|
+
locale,
|
|
1829
|
+
consentMode
|
|
1830
|
+
});
|
|
1831
|
+
if (!result.ok) toast.error(`N\xE3o foi poss\xEDvel iniciar: ${result.reason}`);
|
|
1832
|
+
},
|
|
1833
|
+
[user?.id, locale]
|
|
1834
|
+
);
|
|
1835
|
+
React5.useEffect(() => {
|
|
1836
|
+
const onStart = (ev) => {
|
|
1837
|
+
const detail = ev.detail ?? {};
|
|
1838
|
+
if (retention2.requireConsent) setPending(detail);
|
|
1839
|
+
else void start(detail, retention2.defaultConsentMode);
|
|
1840
|
+
};
|
|
1841
|
+
window.addEventListener(SCRIBE_START_EVENT, onStart);
|
|
1842
|
+
return () => window.removeEventListener(SCRIBE_START_EVENT, onStart);
|
|
1843
|
+
}, [retention2.requireConsent, retention2.defaultConsentMode, start]);
|
|
1844
|
+
const activity = React5.useMemo(() => {
|
|
1845
|
+
if (pending && !live2) {
|
|
1846
|
+
const who = pending.subjectName;
|
|
1847
|
+
return {
|
|
1848
|
+
id: "scribe.session",
|
|
1849
|
+
kind: "recording",
|
|
1850
|
+
state: "pending",
|
|
1851
|
+
label: who ? `${labels.sessionSingular} \xB7 ${who}` : labels.sessionSingular,
|
|
1852
|
+
// A ticked box consents for nobody — the holder does. What it records
|
|
1853
|
+
// is the professional ASSERTING they obtained it, which is the fact
|
|
1854
|
+
// that has to be provable later (LGPD art. 5º II), stamped on the same
|
|
1855
|
+
// row as the audio rather than reconstructed afterwards.
|
|
1856
|
+
confirm: {
|
|
1857
|
+
acknowledge: `Informei ${who ?? "o titular"} de que este atendimento ser\xE1 gravado e obtive o consentimento.`,
|
|
1858
|
+
note: "O \xE1udio fica guardado de forma privada e pode ser apagado quando voc\xEA quiser \u2014 a transcri\xE7\xE3o e o documento permanecem."
|
|
1859
|
+
},
|
|
1860
|
+
actions: [
|
|
1861
|
+
{ intent: "cancel", label: "Cancelar", run: () => setPending(null) },
|
|
1862
|
+
{
|
|
1863
|
+
intent: "start",
|
|
1864
|
+
label: labels.start,
|
|
1865
|
+
primary: true,
|
|
1866
|
+
run: () => void start(pending, retention2.defaultConsentMode)
|
|
1867
|
+
}
|
|
1868
|
+
]
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1898
1871
|
if (live2) {
|
|
1899
1872
|
const actions = [
|
|
1900
1873
|
state === "paused" ? { intent: "resume", label: labels.resume, run: () => void resumeSession() } : { intent: "pause", label: labels.pause, run: () => void pauseSession() },
|
|
@@ -1902,10 +1875,15 @@ function ScribeAssistantBridge({ labels, stt, onOpenSession }) {
|
|
|
1902
1875
|
intent: "stop",
|
|
1903
1876
|
label: labels.finish,
|
|
1904
1877
|
primary: true,
|
|
1878
|
+
// Stopping ends the assistant's part of this, and the app opens the
|
|
1879
|
+
// session. Upload and transcription were never waiting on a click —
|
|
1880
|
+
// the pump carries them — so an "encerrado, gerar?" step in between
|
|
1881
|
+
// was a screen asking permission for work already in progress, on the
|
|
1882
|
+
// surface least able to do the rest of it.
|
|
1905
1883
|
run: async () => {
|
|
1906
1884
|
const id = sessionId;
|
|
1907
1885
|
await endSession();
|
|
1908
|
-
if (id)
|
|
1886
|
+
if (id) onOpenSession?.(id, subjectId);
|
|
1909
1887
|
}
|
|
1910
1888
|
}
|
|
1911
1889
|
];
|
|
@@ -1920,32 +1898,58 @@ function ScribeAssistantBridge({ labels, stt, onOpenSession }) {
|
|
|
1920
1898
|
stream: getCaptureStream
|
|
1921
1899
|
};
|
|
1922
1900
|
}
|
|
1923
|
-
|
|
1901
|
+
const orphan = orphans2[0];
|
|
1902
|
+
if (orphan) {
|
|
1903
|
+
const canResume = Date.now() - orphan.lastTickEpochMs < RESUMABLE_WINDOW_MS;
|
|
1904
|
+
const actions = [];
|
|
1905
|
+
if (canResume) {
|
|
1906
|
+
actions.push({ intent: "resume", label: labels.resume, run: () => void resumeSession() });
|
|
1907
|
+
}
|
|
1908
|
+
actions.push({
|
|
1909
|
+
intent: "stop",
|
|
1910
|
+
label: labels.finish,
|
|
1911
|
+
primary: true,
|
|
1912
|
+
run: async () => {
|
|
1913
|
+
const id = await endSession();
|
|
1914
|
+
dismissOrphan(orphan.id);
|
|
1915
|
+
if (id) onOpenSession?.(id, orphan.subjectId);
|
|
1916
|
+
}
|
|
1917
|
+
});
|
|
1918
|
+
actions.push({
|
|
1919
|
+
intent: "discard",
|
|
1920
|
+
label: labels.discard,
|
|
1921
|
+
run: () => void discardSession(orphan.id)
|
|
1922
|
+
});
|
|
1924
1923
|
return {
|
|
1925
1924
|
id: "scribe.session",
|
|
1926
1925
|
kind: "recording",
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
primary: true,
|
|
1934
|
-
run: () => {
|
|
1935
|
-
onOpenSession?.(finished.id);
|
|
1936
|
-
setFinished(null);
|
|
1937
|
-
}
|
|
1938
|
-
},
|
|
1939
|
-
{ intent: "discard", label: "Depois", run: () => setFinished(null) }
|
|
1940
|
-
]
|
|
1926
|
+
// Not `orphan.accumulatedMs` — see orphanDurationMs: older sessions sit
|
|
1927
|
+
// at 0, and half an hour of audio announced itself as 00:00.
|
|
1928
|
+
elapsedMs: orphanDurationMs(orphan),
|
|
1929
|
+
label: orphan.subjectName ? `${labels.sessionSingular} interrompido \xB7 ${orphan.subjectName}` : `${labels.sessionSingular} interrompido`,
|
|
1930
|
+
state: "paused",
|
|
1931
|
+
actions
|
|
1941
1932
|
};
|
|
1942
1933
|
}
|
|
1943
1934
|
return null;
|
|
1944
|
-
}, [
|
|
1935
|
+
}, [
|
|
1936
|
+
live2,
|
|
1937
|
+
state,
|
|
1938
|
+
elapsedMs2,
|
|
1939
|
+
subjectId,
|
|
1940
|
+
subjectName,
|
|
1941
|
+
sessionId,
|
|
1942
|
+
orphans2,
|
|
1943
|
+
labels,
|
|
1944
|
+
onOpenSession,
|
|
1945
|
+
pending,
|
|
1946
|
+
start,
|
|
1947
|
+
retention2.defaultConsentMode
|
|
1948
|
+
]);
|
|
1945
1949
|
usePublishAssistantActivity(activity);
|
|
1946
|
-
const liveRef =
|
|
1950
|
+
const liveRef = React5.useRef({ live: live2, state, subjectName, sessionId });
|
|
1947
1951
|
liveRef.current = { live: live2, state, subjectName, sessionId };
|
|
1948
|
-
const surface =
|
|
1952
|
+
const surface = React5.useMemo(
|
|
1949
1953
|
() => ({
|
|
1950
1954
|
id: "scribe.session",
|
|
1951
1955
|
pluginId: "scribe",
|
|
@@ -1978,138 +1982,38 @@ function ScribeAssistantBridge({ labels, stt, onOpenSession }) {
|
|
|
1978
1982
|
useAgentSurface(surface);
|
|
1979
1983
|
const supported = isCaptureSupported();
|
|
1980
1984
|
useRegisterAssistantLauncher(
|
|
1981
|
-
live2 ? null : {
|
|
1985
|
+
live2 || pending ? null : {
|
|
1982
1986
|
id: "scribe.start",
|
|
1983
1987
|
kind: "recording",
|
|
1988
|
+
role: SCRIBE_AGENT_ROLE,
|
|
1984
1989
|
label: labels.start,
|
|
1985
1990
|
disabled: !supported,
|
|
1986
1991
|
disabledReason: "Este navegador n\xE3o suporta grava\xE7\xE3o de \xE1udio",
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
}
|
|
1992
|
+
// Already in her thread, so this is the plain request — no need to
|
|
1993
|
+
// re-open the panel it is being pressed inside.
|
|
1994
|
+
run: () => requestScribeStart({})
|
|
1991
1995
|
}
|
|
1992
1996
|
);
|
|
1993
1997
|
return null;
|
|
1994
1998
|
}
|
|
1995
|
-
var SCRIBE_START_EVENT = "scribe:start";
|
|
1996
1999
|
function ScribeShellMount({ labels, retention: retention2, stt, locale, onOpenSession }) {
|
|
1997
|
-
|
|
1998
|
-
const railOffset = useRightRailStore((s) => s.open ? s.width : 0);
|
|
1999
|
-
const contentTop = useContentTop();
|
|
2000
|
-
const bannerRef = React7.useRef(null);
|
|
2001
|
-
useReserveSpace(bannerRef);
|
|
2002
|
-
const [pending, setPending] = React7.useState(null);
|
|
2003
|
-
React7.useEffect(() => {
|
|
2000
|
+
React5.useEffect(() => {
|
|
2004
2001
|
wireScribeStore();
|
|
2005
2002
|
}, []);
|
|
2006
|
-
React7.useEffect(() => {
|
|
2007
|
-
const onStart = (ev) => {
|
|
2008
|
-
const detail = ev.detail ?? {};
|
|
2009
|
-
if (retention2.requireConsent) setPending(detail);
|
|
2010
|
-
else void start(detail, retention2.defaultConsentMode);
|
|
2011
|
-
};
|
|
2012
|
-
window.addEventListener(SCRIBE_START_EVENT, onStart);
|
|
2013
|
-
return () => window.removeEventListener(SCRIBE_START_EVENT, onStart);
|
|
2014
|
-
}, [retention2.requireConsent, retention2.defaultConsentMode, user?.id, locale]);
|
|
2015
|
-
const start = React7.useCallback(
|
|
2016
|
-
async (detail, consentMode) => {
|
|
2017
|
-
if (!user?.id) {
|
|
2018
|
-
toast.error("Fa\xE7a login para gravar um atendimento");
|
|
2019
|
-
return;
|
|
2020
|
-
}
|
|
2021
|
-
const result = await beginSession({
|
|
2022
|
-
userId: user.id,
|
|
2023
|
-
subjectId: detail.subjectId,
|
|
2024
|
-
subjectName: detail.subjectName,
|
|
2025
|
-
appointmentId: detail.appointmentId,
|
|
2026
|
-
templateKeys: detail.templateKeys,
|
|
2027
|
-
locale,
|
|
2028
|
-
consentMode
|
|
2029
|
-
});
|
|
2030
|
-
if (!result.ok) {
|
|
2031
|
-
toast.error(`N\xE3o foi poss\xEDvel iniciar: ${result.reason}`);
|
|
2032
|
-
return;
|
|
2033
|
-
}
|
|
2034
|
-
toast.success(`${labels.sessionSingular} iniciado`);
|
|
2035
|
-
},
|
|
2036
|
-
[user?.id, locale, labels.sessionSingular]
|
|
2037
|
-
);
|
|
2038
2003
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2039
|
-
/* @__PURE__ */ jsx(ScribeAssistantBridge, { labels, stt, onOpenSession }),
|
|
2040
|
-
/* @__PURE__ */ jsx(ScribeRecordingPill, { labels, onOpenSession, mobileOnly: true }),
|
|
2041
2004
|
/* @__PURE__ */ jsx(
|
|
2042
|
-
|
|
2005
|
+
ScribeAssistantBridge,
|
|
2043
2006
|
{
|
|
2044
|
-
open: pending !== null,
|
|
2045
2007
|
labels,
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
const detail = pending;
|
|
2051
|
-
setPending(null);
|
|
2052
|
-
if (detail) void start(detail, mode);
|
|
2053
|
-
}
|
|
2008
|
+
retention: retention2,
|
|
2009
|
+
stt,
|
|
2010
|
+
locale,
|
|
2011
|
+
onOpenSession
|
|
2054
2012
|
}
|
|
2055
2013
|
),
|
|
2056
|
-
|
|
2057
|
-
/* @__PURE__ */ jsx(
|
|
2058
|
-
"div",
|
|
2059
|
-
{
|
|
2060
|
-
ref: bannerRef,
|
|
2061
|
-
className: "pointer-events-auto fixed left-0 z-40",
|
|
2062
|
-
style: { top: contentTop, right: railOffset },
|
|
2063
|
-
children: /* @__PURE__ */ jsx(ScribeRecoveryBanner, { labels, onOpenSession })
|
|
2064
|
-
}
|
|
2065
|
-
),
|
|
2066
|
-
document.body
|
|
2067
|
-
)
|
|
2014
|
+
/* @__PURE__ */ jsx(ScribeRecordingPill, { labels, onOpenSession, mobileOnly: true })
|
|
2068
2015
|
] });
|
|
2069
2016
|
}
|
|
2070
|
-
function useReserveSpace(ref) {
|
|
2071
|
-
React7.useEffect(() => {
|
|
2072
|
-
if (typeof document === "undefined") return;
|
|
2073
|
-
const main = document.querySelector("main");
|
|
2074
|
-
const node = ref.current;
|
|
2075
|
-
if (!main || !node) return;
|
|
2076
|
-
const previous = main.style.paddingTop;
|
|
2077
|
-
const apply = () => {
|
|
2078
|
-
const height = node.getBoundingClientRect().height;
|
|
2079
|
-
main.style.paddingTop = height > 0 ? `${Math.ceil(height)}px` : previous;
|
|
2080
|
-
};
|
|
2081
|
-
apply();
|
|
2082
|
-
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(apply) : null;
|
|
2083
|
-
observer?.observe(node);
|
|
2084
|
-
return () => {
|
|
2085
|
-
observer?.disconnect();
|
|
2086
|
-
main.style.paddingTop = previous;
|
|
2087
|
-
};
|
|
2088
|
-
}, [ref]);
|
|
2089
|
-
}
|
|
2090
|
-
function useContentTop() {
|
|
2091
|
-
const [top, setTop] = React7.useState(56);
|
|
2092
|
-
React7.useEffect(() => {
|
|
2093
|
-
if (typeof document === "undefined") return;
|
|
2094
|
-
const measure = () => {
|
|
2095
|
-
const main2 = document.querySelector("main");
|
|
2096
|
-
if (main2) setTop(Math.round(main2.getBoundingClientRect().top));
|
|
2097
|
-
};
|
|
2098
|
-
measure();
|
|
2099
|
-
window.addEventListener("resize", measure);
|
|
2100
|
-
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(measure) : null;
|
|
2101
|
-
const main = document.querySelector("main");
|
|
2102
|
-
if (observer && main) observer.observe(main);
|
|
2103
|
-
return () => {
|
|
2104
|
-
window.removeEventListener("resize", measure);
|
|
2105
|
-
observer?.disconnect();
|
|
2106
|
-
};
|
|
2107
|
-
}, []);
|
|
2108
|
-
return top;
|
|
2109
|
-
}
|
|
2110
|
-
function requestScribeStart(detail) {
|
|
2111
|
-
window.dispatchEvent(new CustomEvent(SCRIBE_START_EVENT, { detail }));
|
|
2112
|
-
}
|
|
2113
2017
|
|
|
2114
2018
|
// src/lib/prompt.ts
|
|
2115
2019
|
var PROMPT_VERSION = "scribe/narrative@1";
|
|
@@ -2277,15 +2181,15 @@ function DraftPanel({
|
|
|
2277
2181
|
onDiscarded
|
|
2278
2182
|
}) {
|
|
2279
2183
|
const original = generation.markdown ?? "";
|
|
2280
|
-
const [value, setValue] =
|
|
2281
|
-
const [saving, setSaving] =
|
|
2282
|
-
const [committing, setCommitting] =
|
|
2283
|
-
const timer3 =
|
|
2284
|
-
|
|
2184
|
+
const [value, setValue] = React5.useState(generation.markdownEdited ?? original);
|
|
2185
|
+
const [saving, setSaving] = React5.useState(false);
|
|
2186
|
+
const [committing, setCommitting] = React5.useState(false);
|
|
2187
|
+
const timer3 = React5.useRef(null);
|
|
2188
|
+
React5.useEffect(() => {
|
|
2285
2189
|
setValue(generation.markdownEdited ?? generation.markdown ?? "");
|
|
2286
2190
|
}, [generation.id, generation.markdown, generation.markdownEdited]);
|
|
2287
2191
|
const edited = value.trim() !== original.trim();
|
|
2288
|
-
const handleChange =
|
|
2192
|
+
const handleChange = React5.useCallback(
|
|
2289
2193
|
(next) => {
|
|
2290
2194
|
setValue(next);
|
|
2291
2195
|
if (timer3.current) clearTimeout(timer3.current);
|
|
@@ -2296,7 +2200,7 @@ function DraftPanel({
|
|
|
2296
2200
|
},
|
|
2297
2201
|
[generation.id]
|
|
2298
2202
|
);
|
|
2299
|
-
|
|
2203
|
+
React5.useEffect(() => {
|
|
2300
2204
|
return () => {
|
|
2301
2205
|
if (timer3.current) {
|
|
2302
2206
|
clearTimeout(timer3.current);
|
|
@@ -2304,7 +2208,7 @@ function DraftPanel({
|
|
|
2304
2208
|
}
|
|
2305
2209
|
};
|
|
2306
2210
|
}, [generation.id, value]);
|
|
2307
|
-
const handleCommit =
|
|
2211
|
+
const handleCommit = React5.useCallback(async () => {
|
|
2308
2212
|
setCommitting(true);
|
|
2309
2213
|
try {
|
|
2310
2214
|
if (timer3.current) clearTimeout(timer3.current);
|
|
@@ -2494,36 +2398,38 @@ function ScribeSessionPage({
|
|
|
2494
2398
|
stt,
|
|
2495
2399
|
generateEndpoint,
|
|
2496
2400
|
onOpenDocument,
|
|
2497
|
-
onBack
|
|
2401
|
+
onBack,
|
|
2402
|
+
onSessionLoaded
|
|
2498
2403
|
}) {
|
|
2499
|
-
const [session, setSession] =
|
|
2500
|
-
const [segments, setSegments] =
|
|
2501
|
-
const [generations, setGenerations] =
|
|
2502
|
-
const [loading, setLoading] =
|
|
2503
|
-
const [generating, setGenerating] =
|
|
2504
|
-
const [tab, setTab] =
|
|
2505
|
-
const draining2 =
|
|
2506
|
-
const refresh =
|
|
2404
|
+
const [session, setSession] = React5.useState(null);
|
|
2405
|
+
const [segments, setSegments] = React5.useState([]);
|
|
2406
|
+
const [generations, setGenerations] = React5.useState([]);
|
|
2407
|
+
const [loading, setLoading] = React5.useState(true);
|
|
2408
|
+
const [generating, setGenerating] = React5.useState(false);
|
|
2409
|
+
const [tab, setTab] = React5.useState("transcript");
|
|
2410
|
+
const draining2 = React5.useRef(false);
|
|
2411
|
+
const refresh = React5.useCallback(async () => {
|
|
2507
2412
|
const [s, segs, gens] = await Promise.all([
|
|
2508
2413
|
fetchSession(sessionId),
|
|
2509
2414
|
fetchSegments(sessionId),
|
|
2510
2415
|
fetchGenerations(sessionId)
|
|
2511
2416
|
]);
|
|
2512
2417
|
setSession(s);
|
|
2418
|
+
if (s) onSessionLoaded?.(s);
|
|
2513
2419
|
setSegments(segs);
|
|
2514
2420
|
setGenerations(gens);
|
|
2515
2421
|
return { session: s, segments: segs };
|
|
2516
|
-
}, [sessionId]);
|
|
2517
|
-
|
|
2422
|
+
}, [sessionId, onSessionLoaded]);
|
|
2423
|
+
React5.useEffect(() => {
|
|
2518
2424
|
setLoading(true);
|
|
2519
2425
|
void refresh().finally(() => setLoading(false));
|
|
2520
2426
|
}, [refresh]);
|
|
2521
|
-
const pendingStt =
|
|
2427
|
+
const pendingStt = React5.useMemo(
|
|
2522
2428
|
() => segments.filter((s) => s.uploadState === "uploaded" && ["pending", "failed"].includes(s.sttState) && s.sttAttempts < 4),
|
|
2523
2429
|
[segments]
|
|
2524
2430
|
);
|
|
2525
2431
|
const busy = pendingStt.length > 0 || segments.some((s) => s.sttState === "running");
|
|
2526
|
-
|
|
2432
|
+
React5.useEffect(() => {
|
|
2527
2433
|
if (!busy) return;
|
|
2528
2434
|
const id = setInterval(() => {
|
|
2529
2435
|
void (async () => {
|
|
@@ -2552,7 +2458,7 @@ function ScribeSessionPage({
|
|
|
2552
2458
|
return () => clearInterval(id);
|
|
2553
2459
|
}, [busy, pendingStt.length, sessionId, stt, refresh]);
|
|
2554
2460
|
const hasTranscript = segments.some((s) => !s.gap && s.text?.trim());
|
|
2555
|
-
const handleGenerate =
|
|
2461
|
+
const handleGenerate = React5.useCallback(
|
|
2556
2462
|
async (preset) => {
|
|
2557
2463
|
setGenerating(true);
|
|
2558
2464
|
try {
|
|
@@ -2583,7 +2489,7 @@ function ScribeSessionPage({
|
|
|
2583
2489
|
);
|
|
2584
2490
|
const activeGeneration = generations.find((g) => g.id === tab);
|
|
2585
2491
|
useAgentSurface(
|
|
2586
|
-
|
|
2492
|
+
React5.useMemo(
|
|
2587
2493
|
() => ({
|
|
2588
2494
|
id: "scribe.session",
|
|
2589
2495
|
describe: () => ({
|
|
@@ -2738,10 +2644,7 @@ function ScribeHeaderAction({ labels, item, embedded }) {
|
|
|
2738
2644
|
labels,
|
|
2739
2645
|
variant: "outline",
|
|
2740
2646
|
size: embedded ? "sm" : "sm",
|
|
2741
|
-
onStart: () => {
|
|
2742
|
-
openAssistant();
|
|
2743
|
-
requestScribeStart({ subjectId, subjectName });
|
|
2744
|
-
}
|
|
2647
|
+
onStart: () => startScribeSession({ subjectId, subjectName })
|
|
2745
2648
|
}
|
|
2746
2649
|
);
|
|
2747
2650
|
}
|
|
@@ -3272,8 +3175,8 @@ function registerScribeTimelineSource() {
|
|
|
3272
3175
|
}
|
|
3273
3176
|
var BARS = 8;
|
|
3274
3177
|
function DeviceLevel({ deviceId, onSignal }) {
|
|
3275
|
-
const barsRef =
|
|
3276
|
-
|
|
3178
|
+
const barsRef = React5.useRef([]);
|
|
3179
|
+
React5.useEffect(() => {
|
|
3277
3180
|
let cancelled = false;
|
|
3278
3181
|
let stream = null;
|
|
3279
3182
|
let context = null;
|
|
@@ -3334,12 +3237,12 @@ function DeviceLevel({ deviceId, onSignal }) {
|
|
|
3334
3237
|
)) });
|
|
3335
3238
|
}
|
|
3336
3239
|
function ScribeDevicePicker({ open, onOpenChange }) {
|
|
3337
|
-
const [devices, setDevices] =
|
|
3338
|
-
const [selected, setSelected] =
|
|
3339
|
-
const [remember, setRemember] =
|
|
3340
|
-
const [signals, setSignals] =
|
|
3341
|
-
const [busy, setBusy] =
|
|
3342
|
-
|
|
3240
|
+
const [devices, setDevices] = React5.useState([]);
|
|
3241
|
+
const [selected, setSelected] = React5.useState(null);
|
|
3242
|
+
const [remember, setRemember] = React5.useState(true);
|
|
3243
|
+
const [signals, setSignals] = React5.useState({});
|
|
3244
|
+
const [busy, setBusy] = React5.useState(false);
|
|
3245
|
+
React5.useEffect(() => {
|
|
3343
3246
|
if (!open) return;
|
|
3344
3247
|
let cancelled = false;
|
|
3345
3248
|
const load2 = async () => {
|
|
@@ -3360,7 +3263,7 @@ function ScribeDevicePicker({ open, onOpenChange }) {
|
|
|
3360
3263
|
cancelled = true;
|
|
3361
3264
|
};
|
|
3362
3265
|
}, [open]);
|
|
3363
|
-
const markSignal =
|
|
3266
|
+
const markSignal = React5.useCallback((deviceId) => {
|
|
3364
3267
|
setSignals((prev) => prev[deviceId] ? prev : { ...prev, [deviceId]: true });
|
|
3365
3268
|
}, []);
|
|
3366
3269
|
const confirm = async () => {
|
|
@@ -3428,11 +3331,11 @@ function ScribeLivePanel({ labels, onOpenSession }) {
|
|
|
3428
3331
|
const sessionId = useScribeStore((s) => s.sessionId);
|
|
3429
3332
|
const subjectName = useScribeStore((s) => s.subjectName);
|
|
3430
3333
|
const segments = useLiveTranscript((s) => s.segments);
|
|
3431
|
-
const [busy, setBusy] =
|
|
3432
|
-
const [pickerOpen, setPickerOpen] =
|
|
3433
|
-
const [, force] =
|
|
3334
|
+
const [busy, setBusy] = React5.useState(false);
|
|
3335
|
+
const [pickerOpen, setPickerOpen] = React5.useState(false);
|
|
3336
|
+
const [, force] = React5.useReducer((n) => n + 1, 0);
|
|
3434
3337
|
const live2 = state === "recording" || state === "paused" || state === "interrupted";
|
|
3435
|
-
|
|
3338
|
+
React5.useEffect(() => {
|
|
3436
3339
|
if (state !== "recording") return;
|
|
3437
3340
|
const timer3 = setInterval(() => {
|
|
3438
3341
|
if (document.visibilityState === "visible") force();
|
|
@@ -3556,33 +3459,37 @@ function createScribePlugin(options) {
|
|
|
3556
3459
|
registerScribeTimelineSource();
|
|
3557
3460
|
initScribeRuntime({ retention: retention2 });
|
|
3558
3461
|
wireScribeStore();
|
|
3559
|
-
const
|
|
3560
|
-
|
|
3462
|
+
const subjectEntities = options.subjectEntities ?? ["clients", "patients", "people", "persons", "customers"];
|
|
3463
|
+
const sessionPath = options.sessionPath ?? ((args) => scribeSessionPath({ ...args, subjectEntity: subjectEntities[0] }));
|
|
3464
|
+
const openSession = (sessionId, subjectId) => {
|
|
3465
|
+
window.location.hash = sessionPath({ sessionId, subjectId });
|
|
3561
3466
|
};
|
|
3562
|
-
const ShellMount = () =>
|
|
3467
|
+
const ShellMount = () => React5__default.createElement(ScribeShellMount, { labels, retention: retention2, stt: options.stt, locale, onOpenSession: openSession });
|
|
3563
3468
|
ShellMount.displayName = "ScribeShellMount";
|
|
3564
3469
|
const SessionRoute = () => {
|
|
3565
3470
|
const hash = typeof window !== "undefined" ? window.location.hash : "";
|
|
3566
3471
|
const sessionId = hash.split("/scribe/")[1]?.split("/")[0] ?? "";
|
|
3567
3472
|
if (!sessionId) return null;
|
|
3568
|
-
return
|
|
3473
|
+
return React5__default.createElement(ScribeSessionPage, {
|
|
3569
3474
|
sessionId,
|
|
3570
3475
|
labels,
|
|
3571
3476
|
presets,
|
|
3572
3477
|
stt: options.stt,
|
|
3573
3478
|
generateEndpoint,
|
|
3479
|
+
onSessionLoaded: (session) => {
|
|
3480
|
+
if (session.subjectId) openSession(session.id, session.subjectId);
|
|
3481
|
+
},
|
|
3574
3482
|
onBack: () => {
|
|
3575
|
-
window.location.hash =
|
|
3483
|
+
window.location.hash = `/${subjectEntities[0]}`;
|
|
3576
3484
|
},
|
|
3577
3485
|
onOpenDocument: () => {
|
|
3578
|
-
window.location.hash =
|
|
3486
|
+
window.location.hash = `/${subjectEntities[0]}`;
|
|
3579
3487
|
}
|
|
3580
3488
|
});
|
|
3581
3489
|
};
|
|
3582
3490
|
SessionRoute.displayName = "ScribeSessionRoute";
|
|
3583
|
-
const HeaderAction = (props) =>
|
|
3491
|
+
const HeaderAction = (props) => React5__default.createElement(ScribeHeaderAction, { ...props, labels });
|
|
3584
3492
|
HeaderAction.displayName = "ScribeHeaderAction";
|
|
3585
|
-
const subjectEntities = options.subjectEntities ?? ["clients", "patients", "people", "persons", "customers"];
|
|
3586
3493
|
return {
|
|
3587
3494
|
id: "scribe",
|
|
3588
3495
|
name: labels.sessionPlural,
|
|
@@ -3597,6 +3504,10 @@ function createScribePlugin(options) {
|
|
|
3597
3504
|
// impressa passaria a depender de bucket, duas edge functions e chave de
|
|
3598
3505
|
// modelo.
|
|
3599
3506
|
dependencies: ["custom_forms"],
|
|
3507
|
+
// O trabalho deste plugin é de quem está NA SALA — grava o atendimento e o
|
|
3508
|
+
// transforma em documento. O plugin diz o papel; o app diz o nome (no salão,
|
|
3509
|
+
// a Auxiliar de Atendimento). Ver AgentRole em @fayz-ai/core.
|
|
3510
|
+
defaultAgentRole: SCRIBE_AGENT_ROLE,
|
|
3600
3511
|
navigation: [],
|
|
3601
3512
|
routes: [
|
|
3602
3513
|
{
|
|
@@ -3675,6 +3586,6 @@ function createScribePlugin(options) {
|
|
|
3675
3586
|
};
|
|
3676
3587
|
}
|
|
3677
3588
|
|
|
3678
|
-
export { PROMPT_VERSION, SCRIBE_START_EVENT, ScribeDevicePicker, ScribeLivePanel, ScribeSessionPage, ScribeStartButton, beginSession, createScribePlugin, deleteSessionAudio, discardSession, endSession, fetchGenerations, fetchOpenSessions, fetchSegments, fetchSession, fetchSessionsForSubject, formatElapsed, formatOffset, isCaptureSupported, isNarrativeSchema, parseSections, pauseSession, renderTranscript, requestScribeStart, resumeSession, useScribeStore };
|
|
3589
|
+
export { PROMPT_VERSION, SCRIBE_AGENT_ROLE, SCRIBE_START_EVENT, ScribeDevicePicker, ScribeLivePanel, ScribeSessionPage, ScribeStartButton, beginSession, createScribePlugin, deleteSessionAudio, discardSession, endSession, fetchGenerations, fetchOpenSessions, fetchSegments, fetchSession, fetchSessionsForSubject, formatElapsed, formatOffset, isCaptureSupported, isNarrativeSchema, parseSections, pauseSession, renderTranscript, requestScribeStart, resumeSession, scribeSessionPath, startScribeSession, useScribeStore };
|
|
3679
3590
|
//# sourceMappingURL=index.js.map
|
|
3680
3591
|
//# sourceMappingURL=index.js.map
|