Files
FemScoreboard/discord/commands/tts/tts.ts

95 lines
3.1 KiB
TypeScript

import {
AttachmentBuilder,
ChatInputCommandInteraction,
EmbedBuilder,
SlashCommandBuilder,
} from 'discord.js';
import 'dotenv/config';
import { logError } from '../../../logging';
import { requestTTSResponse } from '../../util';
import {
createStatusEmbed,
getRandomLoadingEmoji,
getRandomKawaiiPhrase,
MIKU_COLOR,
} from '../helpers';
const config = {
ttsSettings: {
speaker: process.env.TTS_SPEAKER || 'Vivian',
pitch_change_sem: parseInt(process.env.TTS_PITCH || '0', 10),
},
};
async function ttsCommand(interaction: ChatInputCommandInteraction) {
const text = interaction.options.getString('text');
const speaker = interaction.options.getString('speaker') || config.ttsSettings.speaker;
const pitch = interaction.options.getInteger('pitch') ?? config.ttsSettings.pitch_change_sem;
const instruct = interaction.options.getString('instruct');
// Pick a random loading emoji and phrase for this generation
const loadingEmoji = getRandomLoadingEmoji();
const loadingPhrase = getRandomKawaiiPhrase();
// Initial loading embed
const loadingEmbed = createStatusEmbed(
loadingEmoji,
loadingPhrase,
`Generating audio for: "${text}"`
);
await interaction.reply({ embeds: [loadingEmbed] });
try {
const audio = await requestTTSResponse(text, speaker, pitch, instruct);
const audioBuf = await audio.arrayBuffer();
const audioFile = new AttachmentBuilder(Buffer.from(audioBuf)).setName('mikuified.wav');
// Final embed with the TTS result
const finalEmbed = new EmbedBuilder()
.setColor(MIKU_COLOR)
.setAuthor({ name: 'Miku speaks:' })
.setDescription(text)
.setFooter({
text: `Voice: ${speaker} | Pitch: ${pitch} semitones${instruct ? ` | ${instruct}` : ''}`,
})
.setTimestamp();
await interaction.editReply({
embeds: [finalEmbed],
files: [audioFile],
});
} catch (err) {
const errorEmbed = createStatusEmbed(
loadingEmoji,
loadingPhrase,
`Oops! Something went wrong... 😭\n\`${err}\``
);
await interaction.editReply({ embeds: [errorEmbed] });
logError(`Error while generating TTS: ${err}`);
}
}
export = {
data: new SlashCommandBuilder()
.setName('tts')
.setDescription("Read text in Miku's voice")
.addStringOption((opt) => opt.setName('text').setDescription('Text').setRequired(true))
.addStringOption((opt) =>
opt.setName('speaker').setDescription('Speaker voice to use').setRequired(false)
)
.addIntegerOption((opt) =>
opt
.setName('pitch')
.setDescription('Pitch shift in semitones (default: 0)')
.setRequired(false)
)
.addStringOption((opt) =>
opt
.setName('instruct')
.setDescription('Instruction for how to speak the text')
.setRequired(false)
),
execute: ttsCommand,
config: config,
};