Fix chunked TTS failing on newline-delimited text (e.g. German bullet lists)
splitTextIntoChunks only split on sentence terminators (.!?), so structured text separated by newlines was never chunked — the full page went as one request, causing a TCP timeout that the browser reported as "Failed to fetch". Fix: process each line individually before applying the sentence regex so newline-separated segments become their own split points. Also move generation.js from deferred batch E into the main feature batch C so generateChunkedTts is always defined before the user can click Generate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e6cadd26a3
commit
345bec8a05
@ -8027,16 +8027,25 @@ async function mergeWavBlobs(blobs) {
|
||||
function splitTextIntoChunks(text, maxLen = 800) {
|
||||
const abbrev = /\b(Mr|Mrs|Ms|Dr|Prof|Sr|Jr|vs|etc|e\.g|i\.e)\.\s/g;
|
||||
const safe = text.replace(abbrev, m => m.replace('.', '\x00'));
|
||||
const parts = safe.match(/[^.!?]+[.!?]+\s*/g) || [];
|
||||
const last = safe.replace(/[^.!?]+[.!?]+\s*/g, '').trim();
|
||||
if (last) parts.push(last);
|
||||
const restore = s => s.replace(/\x00/g, '.');
|
||||
if (!parts.length) return [text];
|
||||
|
||||
// Gather segments from each line: sentences first, then any remaining line text.
|
||||
// This ensures newline-delimited text (e.g. German bullet lists) gets split too.
|
||||
const segments = [];
|
||||
for (const line of safe.split('\n')) {
|
||||
const sentences = line.match(/[^.!?]+[.!?]+\s*/g) || [];
|
||||
const rest = line.replace(/[^.!?]+[.!?]+\s*/g, '').trim();
|
||||
segments.push(...sentences);
|
||||
if (rest) segments.push(rest);
|
||||
}
|
||||
if (!segments.length) return [text];
|
||||
|
||||
const chunks = [];
|
||||
let cur = '';
|
||||
for (const p of parts) {
|
||||
if ((cur + p).length > maxLen && cur) { chunks.push(restore(cur.trim())); cur = p; }
|
||||
else cur += p;
|
||||
for (const seg of segments) {
|
||||
const joined = cur ? cur + ' ' + seg.trim() : seg.trim();
|
||||
if (joined.length > maxLen && cur) { chunks.push(restore(cur.trim())); cur = seg.trim(); }
|
||||
else cur = joined;
|
||||
}
|
||||
if (cur.trim()) chunks.push(restore(cur.trim()));
|
||||
return chunks.length ? chunks : [text];
|
||||
|
||||
@ -57,16 +57,25 @@ async function mergeWavBlobs(blobs) {
|
||||
function splitTextIntoChunks(text, maxLen = 800) {
|
||||
const abbrev = /\b(Mr|Mrs|Ms|Dr|Prof|Sr|Jr|vs|etc|e\.g|i\.e)\.\s/g;
|
||||
const safe = text.replace(abbrev, m => m.replace('.', '\x00'));
|
||||
const parts = safe.match(/[^.!?]+[.!?]+\s*/g) || [];
|
||||
const last = safe.replace(/[^.!?]+[.!?]+\s*/g, '').trim();
|
||||
if (last) parts.push(last);
|
||||
const restore = s => s.replace(/\x00/g, '.');
|
||||
if (!parts.length) return [text];
|
||||
|
||||
// Gather segments from each line: sentences first, then any remaining line text.
|
||||
// This ensures newline-delimited text (e.g. German bullet lists) gets split too.
|
||||
const segments = [];
|
||||
for (const line of safe.split('\n')) {
|
||||
const sentences = line.match(/[^.!?]+[.!?]+\s*/g) || [];
|
||||
const rest = line.replace(/[^.!?]+[.!?]+\s*/g, '').trim();
|
||||
segments.push(...sentences);
|
||||
if (rest) segments.push(rest);
|
||||
}
|
||||
if (!segments.length) return [text];
|
||||
|
||||
const chunks = [];
|
||||
let cur = '';
|
||||
for (const p of parts) {
|
||||
if ((cur + p).length > maxLen && cur) { chunks.push(restore(cur.trim())); cur = p; }
|
||||
else cur += p;
|
||||
for (const seg of segments) {
|
||||
const joined = cur ? cur + ' ' + seg.trim() : seg.trim();
|
||||
if (joined.length > maxLen && cur) { chunks.push(restore(cur.trim())); cur = seg.trim(); }
|
||||
else cur = joined;
|
||||
}
|
||||
if (cur.trim()) chunks.push(restore(cur.trim()));
|
||||
return chunks.length ? chunks : [text];
|
||||
|
||||
@ -117,6 +117,7 @@
|
||||
'/static/js/voice-clone.js',
|
||||
'/static/js/voice-library.js',
|
||||
'/static/js/tts-preview.js',
|
||||
'/static/js/generation.js',
|
||||
'/static/js/benchmark.js',
|
||||
'/static/js/stt.js',
|
||||
'/static/js/rehearser-parse.js',
|
||||
@ -152,12 +153,10 @@
|
||||
if (window.initAccessibilityEnhancements) window.initAccessibilityEnhancements();
|
||||
|
||||
// E — post-init modules load in background AFTER the UI is already visible.
|
||||
// Engines, AI backends, generation, and conversation sections load while
|
||||
// the user browses Voices / Clone / Design, not before.
|
||||
// Engines, AI backends, and conversation load while the user browses other tabs.
|
||||
_loadBatch([
|
||||
'/static/js/engines.js',
|
||||
'/static/js/ai-backends.js',
|
||||
'/static/js/generation.js',
|
||||
'/static/js/conversation.js',
|
||||
]);
|
||||
})();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user