Add lsvoices command

This commit is contained in:
2026-05-14 20:20:13 +02:00
parent f2ce38c176
commit 456ec8c83f
2 changed files with 38 additions and 0 deletions

View File

@@ -1,4 +1,5 @@
import { join } from "node:path";
import { AttachmentBuilder } from "discord.js";
import { respond } from "../audio/AudioService.js";
import type { Module } from "./types.js";
@@ -36,5 +37,32 @@ export const ttsSettings: Module = ({ audio, commands, tts, t, rootDir }) => {
}
});
commands.register("lsvoices", (args, message) => {
if (args.length > 1) {
respond(audio, sysmsg, message, t("TOO_MANY_ARGUMENTS"));
return;
}
const sections: string[] = [];
for (const name of tts.list()) {
const engine = tts.get(name);
if (!engine) continue;
const lines = [`=== ${name}${engine.longName} ===`, `default: ${engine.getDefaultVoice()}`];
if (engine.isFreeformVoice()) {
lines.push(`(accepts any voice string — see ${engine.longName} documentation)`);
} else {
const voices = engine.listVoices();
lines.push(`voices (${voices.length}):`);
for (const v of voices) lines.push(` ${v}`);
}
sections.push(lines.join("\n"));
}
const body = sections.join("\n\n") + "\n";
const file = new AttachmentBuilder(Buffer.from(body, "utf8"), { name: "voices.txt" });
void message.reply({
content: `Available TTS engines and voices (${tts.list().length} engines):`,
files: [file],
});
});
commands.register("flush", () => audio.queue.flush());
};

View File

@@ -37,6 +37,16 @@ export abstract class BaseEngine {
return this.voices[voice] != null;
}
/** Returns sorted lowercase voice names known to this engine. Empty if the engine accepts any voice. */
listVoices(): string[] {
return Object.keys(this.voices).sort();
}
/** True when this engine has no static voice table and accepts any voice string. */
isFreeformVoice(): boolean {
return Object.keys(this.voices).length === 0;
}
/** Default implementation: subclass should override either this or getSpeechFile. */
async getSpeech(_text: string, _voice?: string, _params?: VoiceParams): Promise<Response> {
throw new Error(`${this.shortName}: getSpeech not implemented`);