Add lsvoices command
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
|
import { AttachmentBuilder } from "discord.js";
|
||||||
import { respond } from "../audio/AudioService.js";
|
import { respond } from "../audio/AudioService.js";
|
||||||
import type { Module } from "./types.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());
|
commands.register("flush", () => audio.queue.flush());
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,6 +37,16 @@ export abstract class BaseEngine {
|
|||||||
return this.voices[voice] != null;
|
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. */
|
/** Default implementation: subclass should override either this or getSpeechFile. */
|
||||||
async getSpeech(_text: string, _voice?: string, _params?: VoiceParams): Promise<Response> {
|
async getSpeech(_text: string, _voice?: string, _params?: VoiceParams): Promise<Response> {
|
||||||
throw new Error(`${this.shortName}: getSpeech not implemented`);
|
throw new Error(`${this.shortName}: getSpeech not implemented`);
|
||||||
|
|||||||
Reference in New Issue
Block a user