Skip to content

Commit 2362ba5

Browse files
caswelltomclaude
andcommitted
Fix Practice Speaking: strip SOLA_NEXT tags from voice transcript (v1.0.21)
The transcript display was showing raw [SOLA_NEXT]...[/SOLA_NEXT] tags because stripSolaTags() was called on individual streaming tokens — the full tag spans many tokens so the regex never matched. Fixed by accumulating tokens in a displayBuffer and only emitting text up to any [SOLA_NEXT] marker. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7ce642a commit 2362ba5

File tree

4 files changed

+24
-7
lines changed

4 files changed

+24
-7
lines changed

amd/build/voice.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

amd/src/voice.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ define(['local_ai_course_assistant/sse_client'], function(SSE) {
7474
var sseController = null;
7575
/** @type {string} SSE token accumulation buffer for sentence extraction */
7676
var sentenceBuffer = '';
77+
/** @type {string} Accumulates tokens to find and hide the SOLA_NEXT block from transcript */
78+
var displayBuffer = '';
79+
/** @type {number} How many chars of displayBuffer have already been emitted to transcript */
80+
var displayEmitted = 0;
7781
/** @type {number|null} Timer to restart recognition after TTS ends */
7882
var restartTimer = null;
7983
/** @type {string} Derived TTS proxy URL */
@@ -380,6 +384,8 @@ define(['local_ai_course_assistant/sse_client'], function(SSE) {
380384
onTranscriptCb('user', text);
381385
}
382386
sentenceBuffer = '';
387+
displayBuffer = '';
388+
displayEmitted = 0;
383389

384390
var postBody = {
385391
sesskey: cfg.sessKey || '',
@@ -399,11 +405,15 @@ define(['local_ai_course_assistant/sse_client'], function(SSE) {
399405
if (!connected) {
400406
return;
401407
}
402-
// Show streaming text in voice transcript area (strips SOLA_NEXT inline).
403-
var cleanToken = stripSolaTags(token);
404-
if (cleanToken && onTranscriptCb) {
405-
onTranscriptCb('assistant', cleanToken);
408+
// Accumulate for display. Only emit text that precedes [SOLA_NEXT] —
409+
// the tag spans many tokens so single-token regex never matches.
410+
displayBuffer += token;
411+
var solaStart = displayBuffer.indexOf('[SOLA_NEXT]');
412+
var visible = solaStart === -1 ? displayBuffer : displayBuffer.slice(0, solaStart);
413+
if (visible.length > displayEmitted && onTranscriptCb) {
414+
onTranscriptCb('assistant', visible.slice(displayEmitted));
406415
}
416+
displayEmitted = visible.length;
407417
sentenceBuffer += token;
408418
maybeSendSentence();
409419
},

db/upgrade.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,5 +231,12 @@ function xmldb_local_ai_course_assistant_upgrade($oldversion) {
231231
upgrade_plugin_savepoint(true, 2026030804, 'local', 'ai_course_assistant');
232232
}
233233

234+
if ($oldversion < 2026030805) {
235+
// v1.0.21: Fix Practice Speaking transcript showing raw [SOLA_NEXT]...[/SOLA_NEXT]
236+
// tags. Use display accumulator in voice.js so tag is detected across token boundaries.
237+
// No schema changes needed.
238+
upgrade_plugin_savepoint(true, 2026030805, 'local', 'ai_course_assistant');
239+
}
240+
234241
return true;
235242
}

version.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
defined('MOODLE_INTERNAL') || die();
2626

2727
$plugin->component = 'local_ai_course_assistant';
28-
$plugin->version = 2026030804;
28+
$plugin->version = 2026030805;
2929
$plugin->requires = 2024100700; // Moodle 4.5+.
3030
$plugin->maturity = MATURITY_STABLE;
31-
$plugin->release = '1.0.20';
31+
$plugin->release = '1.0.21';

0 commit comments

Comments
 (0)