mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-09 15:59:30 +00:00
fix(text): keep bounded outputs UTF-16 safe (#101355)
Co-authored-by: Alix-007 <li.long15@xydigit.com>
This commit is contained in:
parent
da20b65231
commit
84e5327720
18 changed files with 230 additions and 13 deletions
|
|
@ -115,6 +115,8 @@ const {
|
|||
getTtsProvider,
|
||||
maybeApplyTtsToPayload,
|
||||
resolveTtsConfig,
|
||||
setSummarizationEnabled,
|
||||
setTtsMaxLength,
|
||||
synthesizeSpeech,
|
||||
textToSpeechTelephony,
|
||||
} = await import("./tts.js");
|
||||
|
|
@ -938,6 +940,35 @@ describe("speech-core native voice-note routing", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("truncates long TTS text on a UTF-16 boundary", async () => {
|
||||
const prefsName = "openclaw-speech-core-utf16-truncate-test";
|
||||
const prefsPath = `/tmp/${prefsName}.json`;
|
||||
const cfg = createTtsConfig(prefsName);
|
||||
setTtsMaxLength(prefsPath, 11);
|
||||
setSummarizationEnabled(prefsPath, false);
|
||||
let mediaDir: string | undefined;
|
||||
try {
|
||||
const result = await maybeApplyTtsToPayload({
|
||||
payload: { text: `${"a".repeat(7)}😀tail long enough for TTS` },
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
kind: "final",
|
||||
});
|
||||
|
||||
expect(synthesizeMock).toHaveBeenCalled();
|
||||
const request = requireFirstSynthesisRequest("utf16 truncated TTS request");
|
||||
const spokenText = String(request.text);
|
||||
expect(spokenText).toBe(`${"a".repeat(7)}...`);
|
||||
expect(result.spokenText).toBe(spokenText);
|
||||
mediaDir = result.mediaUrl ? path.dirname(result.mediaUrl) : undefined;
|
||||
} finally {
|
||||
rmSync(prefsPath, { force: true });
|
||||
if (mediaDir) {
|
||||
rmSync(mediaDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("skips block delivery kind in final mode (accumulated final tail synthesizes instead)", async () => {
|
||||
synthesizeMock.mockClear();
|
||||
const cfg = createTtsConfig("openclaw-speech-core-block-kind-tts-test");
|
||||
|
|
|
|||
|
|
@ -33,7 +33,11 @@ import {
|
|||
normalizeOptionalString,
|
||||
} from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { stripMarkdown } from "openclaw/plugin-sdk/text-chunking";
|
||||
import { resolveConfigDir, resolveUserPath } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import {
|
||||
resolveConfigDir,
|
||||
resolveUserPath,
|
||||
truncateUtf16Safe,
|
||||
} from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import {
|
||||
canonicalizeSpeechProviderId,
|
||||
getSpeechProvider,
|
||||
|
|
@ -2028,7 +2032,7 @@ export async function maybeApplyTtsToPayload(params: {
|
|||
logVerbose(
|
||||
`TTS: truncating long text (${textForAudio.length} > ${maxLength}), summarization disabled.`,
|
||||
);
|
||||
textForAudio = `${textForAudio.slice(0, maxLength - 3)}...`;
|
||||
textForAudio = `${truncateUtf16Safe(textForAudio, maxLength - 3)}...`;
|
||||
} else {
|
||||
try {
|
||||
const summary = await summarizeText({
|
||||
|
|
@ -2044,12 +2048,12 @@ export async function maybeApplyTtsToPayload(params: {
|
|||
logVerbose(
|
||||
`TTS: summary exceeded hard limit (${textForAudio.length} > ${config.maxTextLength}); truncating.`,
|
||||
);
|
||||
textForAudio = `${textForAudio.slice(0, config.maxTextLength - 3)}...`;
|
||||
textForAudio = `${truncateUtf16Safe(textForAudio, config.maxTextLength - 3)}...`;
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err as Error;
|
||||
logVerbose(`TTS: summarization failed, truncating instead: ${error.message}`);
|
||||
textForAudio = `${textForAudio.slice(0, maxLength - 3)}...`;
|
||||
textForAudio = `${truncateUtf16Safe(textForAudio, maxLength - 3)}...`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue