that error happens but it stops the code then it sends the message to the target channel 3 times
but ig that happens because the audio file big cuz it works fine with the small audio files theres any possible way to fix this issue?
error:
node:events:497
throw er; // Unhandled ‘error’ event
^
DOMException [AbortError]: This operation was aborted
at new DOMException (node:internal/per_context/domexception:53:5)
at AbortController.abort (node:internal/abort_controller:391:18)
at Timeout. (E:SRTCODESSRT-Discordnode_modules@discordjsrestdistindex.js:680:47)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7)
Emitted ‘error’ event on Client instance at:
at emitUnhandledRejectionOrErr (node:events:402:10)
at process.processTicksAndRejections (node:internal/process/task_queues:84:21)
Node.js v20.14.0
code:
const { Client, GatewayIntentBits, AttachmentBuilder, EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder, ButtonBuilder, ButtonStyle, ModalBuilder, TextInputBuilder, TextInputStyle } = require('discord.js');
const fs = require('fs');
const axios = require('axios');
const ffmpeg = require('fluent-ffmpeg');
const FormData = require('form-data');
const { GoogleAuth } = require('google-auth-library');
const { google } = require('googleapis');
// Define your bot token and channel IDs
const DISCORD_TOKEN = '';
const SPECIFIC_CHANNEL_ID = ''; // Replace with the specific channel ID
const LEAD_CHANNEL_ID = ''; // Replace with the channel ID where the lead form should be sent
// Google Sheets API Setup
const auth = new GoogleAuth({
keyFile: 'credentials.json', // Ensure you have this file with the right permissions
scopes: ['https://www.googleapis.com/auth/spreadsheets']
});
const sheets = google.sheets({ version: 'v4', auth });
const SHEET_ID = '';
const TAB_APPROVED = '';
// Set up the Discord client
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessages] });
// Map to store temporary lead submissions
const leadSubmissions = new Map();
client.once('ready', async () => {
console.log(`Logged in as ${client.user.tag}`);
// Create and send the embed message with the "Submit Lead" button
const leadEmbed = new EmbedBuilder()
.setTitle('Submit a Lead')
.setDescription('Click the button below to submit a lead.')
.setColor(0x00ff00);
const leadButton = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('submitRecord')
.setLabel('Submit Lead')
.setStyle(ButtonStyle.Primary)
);
const leadChannel = client.channels.cache.get(LEAD_CHANNEL_ID);
await leadChannel.send({ embeds: [leadEmbed], components: [leadButton] });
});
// Handle button interaction to display the lead submission modal
client.on('interactionCreate', async interaction => {
if (interaction.isButton() && interaction.customId === 'submitRecord') {
const modal = new ModalBuilder()
.setCustomId('leadFormModal1') // Unique ID for this modal
.setTitle('Lead Submission Form');
const nameInput = new TextInputBuilder()
.setCustomId('name')
.setLabel('Name')
.setStyle(TextInputStyle.Short);
const whatsappInput = new TextInputBuilder()
.setCustomId('whatsapp')
.setLabel('WhatsApp Number')
.setStyle(TextInputStyle.Short);
const emailInput = new TextInputBuilder()
.setCustomId('email')
.setLabel('Email')
.setStyle(TextInputStyle.Short);
const ageInput = new TextInputBuilder()
.setCustomId('age')
.setLabel('Age')
.setStyle(TextInputStyle.Short);
const gradInput = new TextInputBuilder()
.setCustomId('grad')
.setLabel('Grad (Answer with Yes or No)')
.setStyle(TextInputStyle.Short);
const modalComponents = [
new ActionRowBuilder().addComponents(nameInput),
new ActionRowBuilder().addComponents(whatsappInput),
new ActionRowBuilder().addComponents(emailInput),
new ActionRowBuilder().addComponents(ageInput),
new ActionRowBuilder().addComponents(gradInput)
];
modal.addComponents(modalComponents);
await interaction.showModal(modal);
}
// Handle modal submission
if (interaction.isModalSubmit() && interaction.customId === 'leadFormModal1') {
const userId = interaction.user.id;
const leadData = {
name: interaction.fields.getTextInputValue('name'),
whatsapp: interaction.fields.getTextInputValue('whatsapp'),
email: interaction.fields.getTextInputValue('email'),
age: interaction.fields.getTextInputValue('age'),
grad: interaction.fields.getTextInputValue('grad'),
};
// Store lead data temporarily
leadSubmissions.set(userId, leadData);
const row = new ActionRowBuilder()
.addComponents(
new StringSelectMenuBuilder()
.setCustomId('selectRole')
.setPlaceholder('Select a Role')
.addOptions([
{ label: 'Real Estate Cold Caller', value: 'Real Estate Cold Caller' },
{ label: 'Omnikom company', value: 'Omnikom Company' },
{ label: 'SRT', value: 'SRT' },
{ label: 'Nedialo', value: 'Nedialo' },
{ label: 'TP', value: 'Tp' },
{ label: 'Nothing', value: 'Nothing' },
])
);
await interaction.reply({
content: 'Please select one of the following roles:',
components: [row],
ephemeral: true,
});
} else if (interaction.isStringSelectMenu() && interaction.customId === 'selectRole') {
const userId = interaction.user.id;
const selectedValue = interaction.values[0];
const leadData = leadSubmissions.get(userId);
if (leadData) {
leadData.role = selectedValue;
leadSubmissions.set(userId, leadData);
await interaction.update({
content: 'Please send a voice note for assessment.',
components: [],
ephemeral: true,
});
}
}
});
// Handle voice note submission
client.on('messageCreate', async message => {
if (message.author.bot) return;
const userId = message.author.id;
const leadData = leadSubmissions.get(userId);
if (leadData && message.attachments.size > 0) {
const attachment = message.attachments.first();
const filePath = `./temp_${attachment.name}`;
// Download the voice note
const response = await axios.get(attachment.url, { responseType: 'arraybuffer' });
fs.writeFileSync(filePath, response.data);
// Convert and resample the audio
let wavFileName = filePath;
if (!filePath.endsWith('.wav')) {
wavFileName = 'voice_note.wav';
await convertToWav(filePath, wavFileName);
fs.unlinkSync(filePath); // Delete the original file if converted
}
const resampledFileName = wavFileName;
// Delete the original WAV file
message.delete();
// Analyze the voice note using SpeechSuper API
const analysisResult = await assessSpeech(resampledFileName, 'Introduce yourself in English.');
// Combine lead data with analysis result
leadData.analysisResult = analysisResult;
leadSubmissions.delete(userId);
// Send the combined data to the specific channel
const embed = new EmbedBuilder()
.setTitle('New Lead Submission')
.setAuthor({ name: message.author.tag, iconURL: message.author.displayAvatarURL() })
.addFields(
{ name: 'Name', value: leadData.name },
{ name: 'WhatsApp Number', value: leadData.whatsapp },
{ name: 'Email', value: leadData.email },
{ name: 'Age', value: leadData.age },
{ name: 'Grad', value: leadData.grad },
{ name: 'Role', value: leadData.role },
{ name: 'Overall CEFR Score', value: analysisResult.ielts_score.overall.toString() },
{ name: 'Pronunciation', value: analysisResult.ielts_score.pronunciation.toString() },
{ name: 'Fluency', value: analysisResult.ielts_score.fluency.toString() },
{ name: 'Grammar', value: analysisResult.ielts_score.grammar.toString() },
{ name: 'Coherence', value: analysisResult.ielts_score.coherence.toString() },
{ name: 'Vocabulary', value: analysisResult.ielts_score.vocabulary.toString() },
{ name: 'Transcription', value: analysisResult.transcription },
);
const audioFile = new AttachmentBuilder(`${resampledFileName}`);
const targetChannel = client.channels.cache.get(SPECIFIC_CHANNEL_ID);
const sentMessage = await targetChannel.send({ embeds: , files: [audioFile] });
// Upload data to Google Sheets
const dateSubmitted = new Date();
await sheets.spreadsheets.values.append({
spreadsheetId: SHEET_ID,
range: `${TAB_APPROVED}!A1`,
valueInputOption: 'RAW',
resource: {
values: [[
message.author.tag,
leadData.name,
leadData.whatsapp,
leadData.email,
leadData.age,
leadData.grad,
leadData.role,
analysisResult.ielts_score.overall,
analysisResult.ielts_score.pronunciation,
analysisResult.ielts_score.fluency,
analysisResult.ielts_score.grammar,
analysisResult.ielts_score.coherence,
analysisResult.ielts_score.vocabulary,
analysisResult.transcription,
dateSubmitted.toLocaleString(),
sentMessage.url,
'Yes'
]]
}
});
fs.unlinkSync(resampledFileName);
await message.author.send('Thank you! Your lead has been submitted and recorded.');
}
});
// Utility function to convert to WAV
// Helper function to convert audio to WAV format
async function convertToWav(inputPath, outputPath) {
return new Promise((resolve, reject) => {
ffmpeg(inputPath)
.toFormat('wav')
.on('end', resolve)
.on('error', reject)
.save(outputPath);
});
}
// Helper function to resample audio to 16000 Hz
// Function to assess speech using the SpeechSuper API
async function assessSpeech(audioPath, questionPrompt) {
const maxRetries = 3;
let retries = 0;
while (retries < maxRetries) {
try {
const apiKey = "";
const url = `https://api.speechace.co/api/scoring/speech/v9/json?key=${apiKey}&dialect=en-us&user_id=XYZ-ABC-99001`;
const formData = new FormData();
formData.append('include_fluency', '1');
formData.append('include_ielts_subscore', '1');
formData.append('include_unknown_words', '1');
formData.append('pronunciation_score_mode', 'strict');
formData.append('relevance_context', questionPrompt);
formData.append('user_audio_file', fs.createReadStream(audioPath));
const response = await axios.post(url, formData, {
headers: formData.getHeaders(),
});
const result = response.data;
const scores = {
ielts_score: {
overall: result.speech_score.cefr_score.overall || 'N/A',
pronunciation: result.speech_score.cefr_score.pronunciation || 'N/A',
fluency: result.speech_score.cefr_score.fluency || 'N/A',
grammar: result.speech_score.cefr_score.grammar || 'N/A',
coherence: result.speech_score.cefr_score.coherence || 'N/A',
vocabulary: result.speech_score.cefr_score.vocab || 'N/A',
},
relevance: {
class: result.speech_score.relevance.class || 'N/A'
},
transcription: result.speech_score.transcript || 'N/A',
};
const wordPronunciationDetails = result.speech_score.word_score_list.map(wordInfo => ({
word: wordInfo.word || '',
pronunciation: wordInfo.quality_score || 0,
}));
return {
...scores,
word_pronunciation_details: wordPronunciationDetails
};
} catch (error) {
retries += 1;
console.error('Error during speech assessment:', error);
console.log('Retrying...');
}
}
throw new Error('Speech assessment failed after multiple attempts.');
}
// Login to Discord
client.login(DISCORD_TOKEN);
I dont know how to fix this issue but when i send a big audio file that happens it works fine with small ones