@jackdbd/eleventy-plugin-text-to-speech
Version:
Eleventy plugin that uses text-to-speech to generate audio assets for your website, then injects audio players in your HTML.
108 lines • 3.68 kB
JavaScript
import { Readable } from 'node:stream';
import defDebug from 'debug';
import { z } from 'zod';
import { TextToSpeechClient } from '@google-cloud/text-to-speech';
import { cloud_text_to_speech, iam } from '@jackdbd/zod-schemas/gcp';
import { DEBUG_PREFIX } from '../constants.js';
import { validatedDataOrThrow } from '../validation.js';
const debug = defDebug(`${DEBUG_PREFIX}:gcp-text-to-speech`);
export const audioExtension = (audioEncoding) => {
switch (audioEncoding) {
case 'ALAW': {
return 'alaw';
}
case 'LINEAR16': {
return 'l16';
}
case 'MP3': {
return 'mp3';
}
case 'MULAW': {
return 'mulaw';
}
case 'OGG_OPUS': {
return 'opus';
}
default: {
return 'wav';
}
}
};
export const synthesis_config = z
.object({
/**
* Encoding for the generated audio file.
*/
audioEncoding: cloud_text_to_speech.audio_encoding,
/**
* Voice to use for text-to-speech synthesis.
*
* @see [cloud.google.com - Voices supported by the Speech-to-Text API](https://cloud.google.com/text-to-speech/docs/voices)
* @see [cloud.google.com - Different voices might have different prices](https://cloud.google.com/text-to-speech/pricing)
*/
voiceName: cloud_text_to_speech.text
})
.describe('Google Cloud Text-to-Speech synthesize config');
export const synthesize_config = z
.object({
/**
* Text to synthesize into speech using the Google Cloud Text-to-Speech API.
*
* @remarks
* Character limit for the Google Cloud Text-to-Speech API: 5000 characters
*/
text: cloud_text_to_speech.text
})
.describe('Google Cloud Text-to-Speech synthesize config');
/**
* Synthesizes text into speech using the Google Cloud Text-to-Speech API.
*/
export const synthesize = async (client, cfg, text) => {
const { audioEncoding, voiceName } = cfg;
const req = {
audioConfig: { audioEncoding },
input: { text },
voice: { languageCode: voiceName.slice(0, 5), name: voiceName }
};
debug(`synthesize %O`, req);
try {
const [res] = await client.synthesizeSpeech(req);
if (!res.audioContent) {
return {
error: new Error(`Could not synthesize text: no audioContent.`)
};
}
return { value: Readable.from(res.audioContent) };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (err) {
return {
error: new Error(`Could not synthesize text: ${err.message}`)
};
}
};
export const auth_options = z.object({
credentials: iam.client_credentials.optional(),
keyFilename: iam.service_account_json_key_filepath.optional()
});
export const client_config = auth_options.merge(synthesis_config);
/**
* Client for the Google Cloud Text-to-Speech API.
*/
export const defClient = (config) => {
const data = validatedDataOrThrow(config, client_config);
const { audioEncoding, credentials, keyFilename, voiceName } = data;
const client = new TextToSpeechClient({ credentials, keyFilename });
const extension = audioExtension(audioEncoding);
debug(`text will be synthesized into [hash].${extension} using voice ${voiceName}`);
const synthesizeWithClientAndSynthesisConfig = synthesize.bind(null, client, {
audioEncoding,
voiceName
});
return {
config: { audioEncoding, voiceName },
extension,
synthesize: synthesizeWithClientAndSynthesisConfig
};
};
//# sourceMappingURL=gcp-text-to-speech.js.map