Files
tg-chat-bot/src/commands/text-to-speech.ts
T

66 lines
2.3 KiB
TypeScript

import {Message} from "typescript-telegram-bot-api";
import {Command} from "../base/command";
import {AiProvider} from "../model/ai-provider";
import {
resolveTextToSpeechProviderForUser,
sendSynthesizedSpeech,
synthesizeSpeech,
} from "../ai/text-to-speech";
import {logError, replyToMessage} from "../util/utils";
import {Environment} from "../common/environment";
const PROVIDER_ALIASES = new Map<string, AiProvider>([
["openai", AiProvider.OPENAI],
["chatgpt", AiProvider.OPENAI],
["gpt", AiProvider.OPENAI],
["gemini", AiProvider.GEMINI],
["google", AiProvider.GEMINI],
["mistral", AiProvider.MISTRAL],
["ollama", AiProvider.OLLAMA],
]);
function parseProviderToken(token: string | undefined): AiProvider | undefined {
if (!token) return undefined;
return PROVIDER_ALIASES.get(token.toLowerCase().replace(/:$/, ""));
}
export class TextToSpeech extends Command {
command = ["tts", "say", "voice"];
argsMode = "optional" as const;
title = Environment.commandTitles.textToSpeech;
description = Environment.commandDescriptions.textToSpeech;
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
if (!msg.from) return;
const args = match?.[3]?.trim() ?? "";
const replyText = (msg.reply_to_message?.text ?? msg.reply_to_message?.caption ?? "").trim();
const [firstToken = "", ...restTokens] = args.split(/\s+/);
const explicitProvider = parseProviderToken(firstToken);
const text = explicitProvider
? (restTokens.join(" ").trim() || replyText)
: (args || replyText);
if (!text.trim()) {
await replyToMessage({
message: msg,
text: Environment.textToSpeechInstructionText,
}).catch(logError);
return;
}
try {
const resolved = await resolveTextToSpeechProviderForUser(msg.from.id, explicitProvider);
const speech = await synthesizeSpeech({provider: resolved.provider, text});
await sendSynthesizedSpeech(msg, speech);
} catch (e) {
logError(e);
await replyToMessage({
message: msg,
text: e instanceof Error ? e.message : String(e),
}).catch(logError);
}
}
}