refactor: share speech normalization helpers

This commit is contained in:
Peter Steinberger
2026-03-26 21:49:20 +00:00
parent ce9dff1458
commit 29069bd250
4 changed files with 20 additions and 49 deletions

View File

@@ -1,3 +1,10 @@
import {
normalizeApplyTextNormalization,
normalizeLanguageCode,
normalizeSeed,
requireInRange,
} from "openclaw/plugin-sdk/speech-core";
const DEFAULT_ELEVENLABS_BASE_URL = "https://api.elevenlabs.io";
function isValidVoiceId(voiceId: string): boolean {
@@ -12,47 +19,6 @@ function normalizeElevenLabsBaseUrl(baseUrl?: string): string {
return trimmed.replace(/\/+$/, "");
}
function normalizeLanguageCode(code?: string): string | undefined {
const trimmed = code?.trim();
if (!trimmed) {
return undefined;
}
const normalized = trimmed.toLowerCase();
if (!/^[a-z]{2}$/.test(normalized)) {
throw new Error("languageCode must be a 2-letter ISO 639-1 code (e.g. en, de, fr)");
}
return normalized;
}
function normalizeApplyTextNormalization(mode?: string): "auto" | "on" | "off" | undefined {
const trimmed = mode?.trim();
if (!trimmed) {
return undefined;
}
const normalized = trimmed.toLowerCase();
if (normalized === "auto" || normalized === "on" || normalized === "off") {
return normalized;
}
throw new Error("applyTextNormalization must be one of: auto, on, off");
}
function normalizeSeed(seed?: number): number | undefined {
if (seed == null) {
return undefined;
}
const next = Math.floor(seed);
if (!Number.isFinite(next) || next < 0 || next > 4_294_967_295) {
throw new Error("seed must be between 0 and 4294967295");
}
return next;
}
function requireInRange(value: number, min: number, max: number, label: string): void {
if (!Number.isFinite(value) || value < min || value > max) {
throw new Error(`${label} must be between ${min} and ${max}`);
}
}
function assertElevenLabsVoiceSettings(settings: {
stability: number;
similarityBoost: number;

View File

@@ -6,8 +6,7 @@ export { resolveReactionMessageId } from "../channels/plugins/actions/reaction-m
export { optionalStringEnum, stringEnum } from "../agents/schema/typebox.js";
import { Type } from "@sinclair/typebox";
import type { TSchema } from "@sinclair/typebox";
import { stringEnum } from "../agents/schema/typebox.js";
export { optionalStringEnum, stringEnum } from "../agents/schema/typebox.js";
import { stringEnum as createStringEnum } from "../agents/schema/typebox.js";
/** Schema helper for channels that expose button rows on the shared `message` tool. */
export function createMessageToolButtonsSchema(): TSchema {
@@ -17,7 +16,7 @@ export function createMessageToolButtonsSchema(): TSchema {
Type.Object({
text: Type.String(),
callback_data: Type.String(),
style: Type.Optional(stringEnum(["danger", "success", "primary"])),
style: Type.Optional(createStringEnum(["danger", "success", "primary"])),
}),
),
{

View File

@@ -3,4 +3,10 @@
export type { SpeechProviderPlugin } from "../plugins/types.js";
export type { SpeechVoiceOption } from "../tts/provider-types.js";
export { parseTtsDirectives } from "../tts/tts-core.js";
export {
normalizeApplyTextNormalization,
normalizeLanguageCode,
normalizeSeed,
parseTtsDirectives,
requireInRange,
} from "../tts/tts-core.js";

View File

@@ -37,13 +37,13 @@ function trimToUndefined(value?: string): string | undefined {
return trimmed ? trimmed : undefined;
}
function requireInRange(value: number, min: number, max: number, label: string): void {
export function requireInRange(value: number, min: number, max: number, label: string): void {
if (!Number.isFinite(value) || value < min || value > max) {
throw new Error(`${label} must be between ${min} and ${max}`);
}
}
function normalizeLanguageCode(code?: string): string | undefined {
export function normalizeLanguageCode(code?: string): string | undefined {
const trimmed = code?.trim();
if (!trimmed) {
return undefined;
@@ -55,7 +55,7 @@ function normalizeLanguageCode(code?: string): string | undefined {
return normalized;
}
function normalizeApplyTextNormalization(mode?: string): "auto" | "on" | "off" | undefined {
export function normalizeApplyTextNormalization(mode?: string): "auto" | "on" | "off" | undefined {
const trimmed = mode?.trim();
if (!trimmed) {
return undefined;
@@ -67,7 +67,7 @@ function normalizeApplyTextNormalization(mode?: string): "auto" | "on" | "off" |
throw new Error("applyTextNormalization must be one of: auto, on, off");
}
function normalizeSeed(seed?: number): number | undefined {
export function normalizeSeed(seed?: number): number | undefined {
if (seed == null) {
return undefined;
}