refactor(voice-call): share tts deep merge
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
TtsProviderSchema,
|
||||
} from "openclaw/plugin-sdk/voice-call";
|
||||
import { z } from "zod";
|
||||
import { deepMergeDefined } from "./deep-merge.js";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Phone Number Validation
|
||||
@@ -376,45 +377,7 @@ function normalizeVoiceCallTtsConfig(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return TtsConfigSchema.parse({
|
||||
...(defaults ?? {}),
|
||||
...(overrides ?? {}),
|
||||
modelOverrides:
|
||||
defaults?.modelOverrides || overrides?.modelOverrides
|
||||
? {
|
||||
...(defaults?.modelOverrides ?? {}),
|
||||
...(overrides?.modelOverrides ?? {}),
|
||||
}
|
||||
: undefined,
|
||||
elevenlabs:
|
||||
defaults?.elevenlabs || overrides?.elevenlabs
|
||||
? {
|
||||
...(defaults?.elevenlabs ?? {}),
|
||||
...(overrides?.elevenlabs ?? {}),
|
||||
voiceSettings:
|
||||
defaults?.elevenlabs?.voiceSettings || overrides?.elevenlabs?.voiceSettings
|
||||
? {
|
||||
...(defaults?.elevenlabs?.voiceSettings ?? {}),
|
||||
...(overrides?.elevenlabs?.voiceSettings ?? {}),
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
: undefined,
|
||||
openai:
|
||||
defaults?.openai || overrides?.openai
|
||||
? {
|
||||
...(defaults?.openai ?? {}),
|
||||
...(overrides?.openai ?? {}),
|
||||
}
|
||||
: undefined,
|
||||
edge:
|
||||
defaults?.edge || overrides?.edge
|
||||
? {
|
||||
...(defaults?.edge ?? {}),
|
||||
...(overrides?.edge ?? {}),
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
return TtsConfigSchema.parse(deepMergeDefined(defaults ?? {}, overrides ?? {}));
|
||||
}
|
||||
|
||||
export function normalizeVoiceCallConfig(config: VoiceCallConfigInput): VoiceCallConfig {
|
||||
|
||||
23
extensions/voice-call/src/deep-merge.ts
Normal file
23
extensions/voice-call/src/deep-merge.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
const BLOCKED_MERGE_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
||||
|
||||
export function deepMergeDefined(base: unknown, override: unknown): unknown {
|
||||
if (!isPlainObject(base) || !isPlainObject(override)) {
|
||||
return override === undefined ? base : override;
|
||||
}
|
||||
|
||||
const result: Record<string, unknown> = { ...base };
|
||||
for (const [key, value] of Object.entries(override)) {
|
||||
if (BLOCKED_MERGE_KEYS.has(key) || value === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const existing = result[key];
|
||||
result[key] = key in result ? deepMergeDefined(existing, value) : value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
||||
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { VoiceCallTtsConfig } from "./config.js";
|
||||
import type { CoreConfig } from "./core-bridge.js";
|
||||
import { deepMergeDefined } from "./deep-merge.js";
|
||||
import { convertPcmToMulaw8k } from "./telephony-audio.js";
|
||||
|
||||
export type TelephonyTtsRuntime = {
|
||||
@@ -20,8 +21,6 @@ export type TelephonyTtsProvider = {
|
||||
synthesizeForTelephony: (text: string) => Promise<Buffer>;
|
||||
};
|
||||
|
||||
const BLOCKED_MERGE_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
||||
|
||||
export function createTelephonyTtsProvider(params: {
|
||||
coreConfig: CoreConfig;
|
||||
ttsOverride?: VoiceCallTtsConfig;
|
||||
@@ -79,28 +78,5 @@ function mergeTtsConfig(
|
||||
if (!base) {
|
||||
return override;
|
||||
}
|
||||
return deepMerge(base, override);
|
||||
}
|
||||
|
||||
function deepMerge<T>(base: T, override: T): T {
|
||||
if (!isPlainObject(base) || !isPlainObject(override)) {
|
||||
return override;
|
||||
}
|
||||
const result: Record<string, unknown> = { ...base };
|
||||
for (const [key, value] of Object.entries(override)) {
|
||||
if (BLOCKED_MERGE_KEYS.has(key) || value === undefined) {
|
||||
continue;
|
||||
}
|
||||
const existing = (base as Record<string, unknown>)[key];
|
||||
if (isPlainObject(existing) && isPlainObject(value)) {
|
||||
result[key] = deepMerge(existing, value);
|
||||
} else {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
return result as T;
|
||||
}
|
||||
|
||||
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
||||
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
||||
return deepMergeDefined(base, override) as VoiceCallTtsConfig;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user