Skip to content

Commit 838c9a4

Browse files
Enhance scribe control and update script references
- Introduced `settleScribeBeforeSubmit` in `app.js` to ensure the scribe controller is properly stopped before draft submission, with error handling and logging. - Updated script references in `index.html` for `scribe.js` and `app.js` to new versions. - Added functions in `scribe.js` to manage idle state, including `idleWaiters`, `resolveIdleWaiters`, and `waitForIdle`, improving control over the scribe's state. - Implemented `stopAndWaitForIdle` function in the controller for orderly operation. - Noted differences in binary files `Buffaly.CodexEmbedded.Core.dll` and `Buffaly.CodexEmbedded.Web.dll`.
1 parent 875c8a1 commit 838c9a4

5 files changed

Lines changed: 68 additions & 2 deletions

File tree

Buffaly.CodexEmbedded.Web/wwwroot/app.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3794,6 +3794,25 @@ function initializeScribeControl() {
37943794
});
37953795
}
37963796

3797+
async function settleScribeBeforeSubmit() {
3798+
if (!scribeController) {
3799+
return;
3800+
}
3801+
3802+
try {
3803+
if (typeof scribeController.stopAndWaitForIdle === "function") {
3804+
await scribeController.stopAndWaitForIdle();
3805+
return;
3806+
}
3807+
3808+
if (scribeController.recording && typeof scribeController.stop === "function") {
3809+
await scribeController.stop();
3810+
}
3811+
} catch (error) {
3812+
appendLog(`[voice] failed to finalize dictation before send: ${error}`);
3813+
}
3814+
}
3815+
37973816
function getQueuedTurnsForSession(sessionId) {
37983817
if (!sessionId) {
37993818
return [];
@@ -7085,6 +7104,7 @@ function cancelCurrentTurn() {
70857104

70867105
promptForm.addEventListener("submit", async (event) => {
70877106
event.preventDefault();
7107+
await settleScribeBeforeSubmit();
70887108
const prompt = promptInput.value.trim();
70897109
const images = pendingComposerImages.map((x) => ({ ...x }));
70907110
const usePlanMode = planModeNextTurn === true;

Buffaly.CodexEmbedded.Web/wwwroot/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,8 @@
381381
</div>
382382
<script src="theme.js?v=20260225-settings1"></script>
383383
<script src="sessionTimeline.js?v=20260227-turnanchor2"></script>
384-
<script src="scribe.js?v=20260225-scribe1"></script>
384+
<script src="scribe.js?v=20260302-scribe2"></script>
385385
<script src="app.shared.js?v=20260228-cleanup1"></script>
386-
<script src="app.js?v=20260227-sidebarsearch2"></script>
386+
<script src="app.js?v=20260302-dictation-send1"></script>
387387
</body>
388388
</html>

Buffaly.CodexEmbedded.Web/wwwroot/scribe.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@
278278
let disposed = false;
279279
let recordingContext = null;
280280
let skipFinalTranscriptionForCapture = false;
281+
let idleWaiters = [];
281282

282283
function log(message) {
283284
if (onLog) {
@@ -297,6 +298,31 @@
297298
}
298299
}
299300

301+
function resolveIdleWaiters() {
302+
if (isRecording || isProcessing || idleWaiters.length === 0) {
303+
return;
304+
}
305+
306+
const waiters = idleWaiters;
307+
idleWaiters = [];
308+
for (const resolve of waiters) {
309+
try {
310+
resolve();
311+
} catch {
312+
}
313+
}
314+
}
315+
316+
function waitForIdle() {
317+
if (!isRecording && !isProcessing) {
318+
return Promise.resolve();
319+
}
320+
321+
return new Promise((resolve) => {
322+
idleWaiters.push(resolve);
323+
});
324+
}
325+
300326
function setState(state) {
301327
if (state === "recording") {
302328
button.classList.add("is-recording");
@@ -689,6 +715,7 @@
689715
isRecording = false;
690716
recordingContext = null;
691717
setState("idle");
718+
resolveIdleWaiters();
692719
log(`[voice] unable to start microphone capture: ${error}`);
693720
}
694721
}
@@ -765,6 +792,20 @@
765792
isProcessing = false;
766793
recordingContext = null;
767794
setState("idle");
795+
resolveIdleWaiters();
796+
}
797+
798+
async function stopAndWaitForIdle() {
799+
if (disposed) {
800+
return;
801+
}
802+
803+
if (isRecording) {
804+
await stopCapture();
805+
return;
806+
}
807+
808+
await waitForIdle();
768809
}
769810

770811
async function onClick() {
@@ -796,6 +837,7 @@
796837
visualizer.dispose();
797838
button.classList.remove("speaking");
798839
setState("idle");
840+
resolveIdleWaiters();
799841
delete button.__scribeController;
800842
}
801843

@@ -804,9 +846,13 @@
804846
const controller = {
805847
start: startCapture,
806848
stop: stopCapture,
849+
stopAndWaitForIdle,
807850
dispose,
808851
get recording() {
809852
return isRecording;
853+
},
854+
get processing() {
855+
return isProcessing;
810856
}
811857
};
812858

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)