mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-13 02:01:16 +00:00
163 lines
4.5 KiB
TypeScript
163 lines
4.5 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { buildOpenAISpeechProvider } from "./speech-provider.js";
|
|
|
|
describe("buildOpenAISpeechProvider", () => {
|
|
const originalFetch = globalThis.fetch;
|
|
|
|
afterEach(() => {
|
|
globalThis.fetch = originalFetch;
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("normalizes provider-owned speech config from raw provider config", () => {
|
|
const provider = buildOpenAISpeechProvider();
|
|
const resolved = provider.resolveConfig?.({
|
|
cfg: {} as never,
|
|
timeoutMs: 30_000,
|
|
rawConfig: {
|
|
providers: {
|
|
openai: {
|
|
apiKey: "sk-test",
|
|
baseUrl: "https://example.com/v1/",
|
|
model: "tts-1",
|
|
voice: "alloy",
|
|
speed: 1.25,
|
|
instructions: " Speak warmly ",
|
|
responseFormat: " WAV ",
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(resolved).toEqual({
|
|
apiKey: "sk-test",
|
|
baseUrl: "https://example.com/v1",
|
|
model: "tts-1",
|
|
voice: "alloy",
|
|
speed: 1.25,
|
|
instructions: "Speak warmly",
|
|
responseFormat: "wav",
|
|
});
|
|
});
|
|
|
|
it("parses OpenAI directive tokens against the resolved base url", () => {
|
|
const provider = buildOpenAISpeechProvider();
|
|
|
|
expect(
|
|
provider.parseDirectiveToken?.({
|
|
key: "voice",
|
|
value: "alloy",
|
|
policy: {
|
|
allowVoice: true,
|
|
allowModelId: true,
|
|
},
|
|
providerConfig: {
|
|
baseUrl: "https://api.openai.com/v1/",
|
|
},
|
|
} as never),
|
|
).toEqual({
|
|
handled: true,
|
|
overrides: { voice: "alloy" },
|
|
});
|
|
|
|
expect(
|
|
provider.parseDirectiveToken?.({
|
|
key: "model",
|
|
value: "kokoro-custom-model",
|
|
policy: {
|
|
allowVoice: true,
|
|
allowModelId: true,
|
|
},
|
|
providerConfig: {
|
|
baseUrl: "https://api.openai.com/v1/",
|
|
},
|
|
} as never),
|
|
).toEqual({
|
|
handled: false,
|
|
});
|
|
});
|
|
|
|
it("preserves talk responseFormat overrides", () => {
|
|
const provider = buildOpenAISpeechProvider();
|
|
|
|
expect(
|
|
provider.resolveTalkConfig?.({
|
|
cfg: {} as never,
|
|
timeoutMs: 30_000,
|
|
baseTtsConfig: {
|
|
providers: {
|
|
openai: {
|
|
apiKey: "sk-base",
|
|
responseFormat: "mp3",
|
|
},
|
|
},
|
|
},
|
|
talkProviderConfig: {
|
|
apiKey: "sk-talk",
|
|
responseFormat: " WAV ",
|
|
},
|
|
}),
|
|
).toMatchObject({
|
|
apiKey: "sk-talk",
|
|
responseFormat: "wav",
|
|
});
|
|
});
|
|
|
|
it("uses wav for Groq-compatible OpenAI TTS endpoints", async () => {
|
|
const provider = buildOpenAISpeechProvider();
|
|
const fetchMock = vi.fn(async (_url: string, init?: RequestInit) => {
|
|
expect(init?.body).toBeTruthy();
|
|
const body = JSON.parse(String(init?.body)) as { response_format?: string };
|
|
expect(body.response_format).toBe("wav");
|
|
return new Response(new Uint8Array([1, 2, 3]), { status: 200 });
|
|
});
|
|
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
|
|
|
const result = await provider.synthesize({
|
|
text: "hello",
|
|
cfg: {} as never,
|
|
providerConfig: {
|
|
apiKey: "sk-test",
|
|
baseUrl: "https://api.groq.com/openai/v1",
|
|
model: "canopylabs/orpheus-v1-english",
|
|
voice: "daniel",
|
|
},
|
|
target: "audio-file",
|
|
timeoutMs: 1_000,
|
|
});
|
|
|
|
expect(result.outputFormat).toBe("wav");
|
|
expect(result.fileExtension).toBe(".wav");
|
|
expect(result.voiceCompatible).toBe(false);
|
|
});
|
|
|
|
it("honors explicit responseFormat overrides and clears voice-note compatibility when not opus", async () => {
|
|
const provider = buildOpenAISpeechProvider();
|
|
const fetchMock = vi.fn(async (_url: string, init?: RequestInit) => {
|
|
expect(init?.body).toBeTruthy();
|
|
const body = JSON.parse(String(init?.body)) as { response_format?: string };
|
|
expect(body.response_format).toBe("wav");
|
|
return new Response(new Uint8Array([1, 2, 3]), { status: 200 });
|
|
});
|
|
globalThis.fetch = fetchMock as unknown as typeof fetch;
|
|
|
|
const result = await provider.synthesize({
|
|
text: "hello",
|
|
cfg: {} as never,
|
|
providerConfig: {
|
|
apiKey: "sk-test",
|
|
baseUrl: "https://proxy.example.com/openai/v1",
|
|
model: "canopylabs/orpheus-v1-english",
|
|
voice: "daniel",
|
|
responseFormat: "wav",
|
|
},
|
|
target: "voice-note",
|
|
timeoutMs: 1_000,
|
|
});
|
|
|
|
expect(result.outputFormat).toBe("wav");
|
|
expect(result.fileExtension).toBe(".wav");
|
|
expect(result.voiceCompatible).toBe(false);
|
|
});
|
|
});
|