SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
f778c12 verified
Raw
History Blame Contribute Delete
6.1 kB
import { Option, type Command } from "commander";
import { callGateway } from "../../gateway/call.js";
import { defaultRuntime } from "../../runtime.js";
import { normalizeSpeechProviderId } from "../../tts/provider-registry.js";
import { runCommandWithRuntime } from "../cli-utils.js";
import { emitJsonOrText, formatEnvelopeForText, providerSummaryText } from "./output.js";
import { resolveModelRefOverride, resolveTransport } from "./shared.js";
import {
runTtsConvert,
runTtsPersonas,
runTtsProviders,
runTtsStateMutation,
runTtsVoices,
} from "./tts-runtime.js";
function registerTransportTtsCommand<T>(
command: Command,
defaultTransport: "local" | "gateway",
run: (opts: Record<string, unknown>, transport: "local" | "gateway") => Promise<T>,
formatText: (value: T) => string = (value) => JSON.stringify(value, null, 2),
): void {
command
.option("--local", "Force local execution", false)
.option("--gateway", "Force gateway execution", false)
.option("--json", "Output JSON", false)
.action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const transport = resolveTransport({
local: Boolean(opts.local),
gateway: Boolean(opts.gateway),
supported: ["local", "gateway"],
defaultTransport,
});
const result = await run(opts, transport);
emitJsonOrText(defaultRuntime, Boolean(opts.json), result, formatText);
});
});
}
export function registerTtsCapabilityCommands(capability: Command): void {
const tts = capability.command("tts").description("Text to speech");
registerTransportTtsCommand(
tts
.command("convert")
.description("Convert text to speech")
.requiredOption("--text <text>", "Input text")
.option("--channel <id>", "Channel hint")
.option("--voice <id>", "Voice hint")
.option("--provider <id>", "Speech provider id")
.option("--model <provider/model>", "Model override")
.option("--output <path>", "Output path"),
"local",
async (opts, transport) => {
const modelRef = resolveModelRefOverride(opts.model as string | undefined);
if (opts.model && !modelRef.provider) {
throw new Error("TTS model overrides must use the form <provider/model>.");
}
const provider = normalizeSpeechProviderId(
typeof opts.provider === "string" && opts.provider.trim()
? opts.provider.trim()
: modelRef.provider,
);
const modelProvider = normalizeSpeechProviderId(modelRef.provider);
if (provider && modelProvider && provider !== modelProvider) {
throw new Error("TTS --provider must match the provider in --model.");
}
return await runTtsConvert({
text: String(opts.text),
channel: opts.channel as string | undefined,
provider,
modelId: modelProvider ? modelRef.model : undefined,
voiceId: opts.voice as string | undefined,
output: opts.output as string | undefined,
transport,
});
},
formatEnvelopeForText,
);
tts
.command("voices")
.description("List voices for a TTS provider")
.option("--provider <id>", "Speech provider id")
.option("--json", "Output JSON", false)
.action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const voices = await runTtsVoices(opts.provider as string | undefined);
emitJsonOrText(defaultRuntime, Boolean(opts.json), voices, providerSummaryText);
});
});
registerTransportTtsCommand(
tts
.command("providers")
.description("List speech providers")
.option("--agent <id>", "Agent whose provider state should be inspected"),
"local",
(opts, transport) => runTtsProviders(transport, opts.agent as string | undefined),
);
registerTransportTtsCommand(
tts.command("personas").description("List TTS personas"),
"local",
(_, transport) => runTtsPersonas(transport),
);
tts
.command("status")
.description("Show TTS status")
.option("--gateway", "Force gateway execution", false)
.option("--json", "Output JSON", false)
.action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const transport = resolveTransport({
gateway: Boolean(opts.gateway),
supported: ["gateway"],
defaultTransport: "gateway",
});
const result = await callGateway({
method: "tts.status",
timeoutMs: 30_000,
});
emitJsonOrText(defaultRuntime, Boolean(opts.json), { transport, ...result }, (value) =>
JSON.stringify(value, null, 2),
);
});
});
for (const [commandName, capabilityId] of [
["enable", "tts.enable"],
["disable", "tts.disable"],
] as const) {
registerTransportTtsCommand(
tts
.command(commandName)
.description(`${commandName === "enable" ? "Enable" : "Disable"} TTS`),
"gateway",
(_, transport) => runTtsStateMutation({ capability: capabilityId, transport }),
);
}
registerTransportTtsCommand(
tts
.command("set-provider")
.description("Set the active TTS provider")
.requiredOption("--provider <id>", "Speech provider id"),
"gateway",
(opts, transport) =>
runTtsStateMutation({
capability: "tts.set-provider",
provider: String(opts.provider),
transport,
}),
);
registerTransportTtsCommand(
tts
.command("set-persona")
.description("Set the active TTS persona")
.addOption(new Option("--persona <id>", "TTS persona id").conflicts("off"))
.option("--off", "Disable the active TTS persona", false),
"gateway",
(opts, transport) => {
if (!opts.off && !opts.persona) {
throw new Error("--persona is required unless --off is set");
}
return runTtsStateMutation({
capability: "tts.set-persona",
persona: opts.off ? null : String(opts.persona),
transport,
});
},
);
}