UNPKG

@aristech-org/tts-client

Version:

A Node.js client library for the Aristech Text-to-Speech API

196 lines (195 loc) 6.8 kB
import * as grpc from '@grpc/grpc-js'; import { ClearCacheRequest, PhonesetRequest, SpeechRequest, SpeechServiceClient, SsmlDocumentationRequest, TranscriptionRequest, VoiceListRequest } from './generated/TTSServices.js'; import fs from 'fs'; export * from './generated/TTSTypes.js'; export { PhonesetRequest, PhonesetResponse, SpeechRequest, SpeechResponse, SpeechServiceClient, SsmlDocumentationRequest, SsmlDocumentationResponse, TranscriptionRequest, TranscriptionResponse, VoiceListRequest } from './generated/TTSServices.js'; export class TtsClient { cOptions; constructor(options) { this.cOptions = options; } /** * Lists all available voices. */ listVoices(request) { return new Promise((res, rej) => { const client = this.getClient(); const req = VoiceListRequest.create(request); const stream = client.getVoiceList(req); const voices = []; stream.on('data', (voice) => { voices.push(voice); }); stream.on('end', () => { res(voices); }); stream.on('error', (err) => { rej(err); }); }); } /** * Creates a stream of audio data from the given text. * @param request The request object * @returns The response stream */ streamAudio(request) { return new Promise(async (res, rej) => { const client = this.getClient(); const req = SpeechRequest.create(request); const stream = client.getSpeech(req); res(stream); }); } /** * Creates an audio buffer from the given text. * @param request The request object * @returns The audio buffer */ synthesize(request) { return new Promise(async (res, rej) => { const stream = await this.streamAudio(request); const rawChunks = []; stream.on('data', (msg) => { const chunk = Buffer.from(msg.data); rawChunks.push(chunk); }); stream.on('end', () => { res(Buffer.concat(rawChunks)); }); stream.on('error', (err) => { rej(err); }); }); } /** * This is an alias for the `synthesize` method. */ audioBuffer(request) { return this.synthesize(request); } /** * Retrieves the phoneset for the given voice. * @param request The request object * @returns The phoneset response */ getPhoneset(request) { return new Promise((res, rej) => { const client = this.getClient(); const req = PhonesetRequest.create(request); client.getPhoneset(req, (err, response) => { if (err) { rej(err); return; } res(response); }); }); } /** * Retrieves the transcription for the given request. * @param request The request object * @returns The transcription response */ getTranscription(request) { return new Promise((res, rej) => { const client = this.getClient(); const req = TranscriptionRequest.create(request); client.getTranscription(req, (err, response) => { if (err) { rej(err); return; } res(response); }); }); } /** * Clears the cache of the server, removing all cached audio data. * @param request The request object * @returns The clear cache response */ clearCache(request = {}) { return new Promise((res, rej) => { const client = this.getClient(); const req = ClearCacheRequest.create(request); client.clearCache(req, (err, response) => { if (err) { rej(err); return; } res(response); }); }); } /** * Retrieves SSML documentation for a specific voice. * @param request The request object containing voice_id and optional locale * @returns The SSML documentation response */ getSsmlDocumentation(request) { return new Promise((res, rej) => { const client = this.getClient(); const req = SsmlDocumentationRequest.create(request); client.getSsmlDocumentation(req, (err, response) => { if (err) { rej(err); return; } res(response); }); }); } getClient() { const { rootCert: rootCertPath, rootCertContent, auth, grpcClientOptions } = this.cOptions; let host = this.cOptions.host || 'localhost:8423'; let ssl = this.cOptions.ssl === true; let rootCert = null; if (rootCertContent) { rootCert = Buffer.from(rootCertContent); } else if (rootCertPath) { rootCert = fs.readFileSync(rootCertPath); } const sslExplicit = typeof this.cOptions.ssl === 'boolean' || !!rootCert; const portRe = /[^:]+:([0-9]+)$/; if (portRe.test(host)) { // In case a port was provided but ssl was not specified // ssl is assumed when the port matches 8424 const [, portStr] = host.match(portRe); const hostPort = parseInt(portStr, 10); if (!sslExplicit) { if (hostPort === 8424) { ssl = true; } else { ssl = false; } } } else { // In case no port was provided, depending on the ssl settings // at the default non ssl port 8423 or ssl port 8424 if (sslExplicit && ssl) { host = `${host}:8424`; } else { host = `${host}:8423`; } } let creds = grpc.credentials.createInsecure(); if (ssl || rootCert) { creds = grpc.credentials.createSsl(rootCert); if (auth) { const callCreds = grpc.credentials.createFromMetadataGenerator((_, cb) => { const meta = new grpc.Metadata(); meta.add('token', auth.token); meta.add('secret', auth.secret); cb(null, meta); }); creds = grpc.credentials.combineChannelCredentials(creds, callCreds); } } return new SpeechServiceClient(host, creds, grpcClientOptions); } }