diff --git a/packages/text-to-speech/src/index.ts b/packages/text-to-speech/src/index.ts index 9f8a44d55..07233a0c8 100644 --- a/packages/text-to-speech/src/index.ts +++ b/packages/text-to-speech/src/index.ts @@ -90,6 +90,7 @@ export const textToSpeechHandler = Sentry.GCPFunction.wrapHttpFunction( console.error(e) return res.status(200).send('UNAUTHENTICATED') } + // validate input const input = req.body as HTMLInput const id = input.id const bucket = input.bucket @@ -97,26 +98,30 @@ export const textToSpeechHandler = Sentry.GCPFunction.wrapHttpFunction( return res.status(200).send('Invalid data') } try { + // audio file to be saved in GCS const audioFileName = `speech/${id}.mp3` const audioFile = createGCSFile(bucket, audioFileName) const audioStream = audioFile.createWriteStream({ resumable: true, }) as NodeJS.WriteStream - const speechMarksFileName = `speech/${id}.json` - const speechMarksFile = createGCSFile(bucket, speechMarksFileName) - const speechMarksStream = speechMarksFile.createWriteStream({ - resumable: true, - }) as NodeJS.WriteStream + // synthesize text to speech const startTime = Date.now() - await synthesizeTextToSpeech({ + const { speechMarks } = await synthesizeTextToSpeech({ ...input, textType: 'html', audioStream, - speechMarksStream, }) console.info( `Synthesize text to speech completed in ${Date.now() - startTime} ms` ) + // speech marks file to be saved in GCS + const speechMarksFileName = `speech/${id}.json` + await uploadToBucket( + speechMarksFileName, + Buffer.from(JSON.stringify(speechMarks)), + bucket + ) + // update speech state const updated = await updateSpeech( id, token, @@ -124,12 +129,10 @@ export const textToSpeechHandler = Sentry.GCPFunction.wrapHttpFunction( audioFileName, speechMarksFileName ) - if (!updated) { console.error('Failed to update speech') return res.status(500).send({ errorCodes: 'DB_ERROR' }) } - console.info('Text to speech cloud function completed') res.send('OK') } catch (e) { diff --git a/packages/text-to-speech/src/textToSpeech.ts b/packages/text-to-speech/src/textToSpeech.ts index f9836973a..99b133b75 100644 --- a/packages/text-to-speech/src/textToSpeech.ts +++ b/packages/text-to-speech/src/textToSpeech.ts @@ -18,7 +18,6 @@ export interface TextToSpeechInput { rate?: number complimentaryVoice?: string audioStream?: NodeJS.ReadWriteStream - speechMarksStream?: NodeJS.ReadWriteStream } export interface TextToSpeechOutput { @@ -42,7 +41,6 @@ export const synthesizeTextToSpeech = async ( } const textType = input.textType || 'html' const audioStream = input.audioStream || new PassThrough() - const speechMarksStream = input.speechMarksStream || new PassThrough() const speechConfig = SpeechConfig.fromSubscription( process.env.AZURE_SPEECH_KEY, process.env.AZURE_SPEECH_REGION @@ -93,15 +91,13 @@ export const synthesizeTextToSpeech = async ( e.text }` ) - const speechMark: SpeechMark = { + speechMarks.push({ word: e.text, time: (timeOffset + e.audioOffset) / 10000, start: e.textOffset, length: e.wordLength, type: 'word', - } - speechMarks.push(speechMark) - speechMarksStream.write(Buffer.from(JSON.stringify(speechMark))) + }) } synthesizer.bookmarkReached = (s, e) => { @@ -110,13 +106,11 @@ export const synthesizeTextToSpeech = async ( e.audioOffset / 10000 }ms, bookmark text: ${e.text}` ) - const speechMark: SpeechMark = { + speechMarks.push({ word: e.text, time: (timeOffset + e.audioOffset) / 10000, type: 'bookmark', - } - speechMarks.push(speechMark) - speechMarksStream.write(Buffer.from(JSON.stringify(speechMark))) + }) } const speakSsmlAsyncPromise = ( @@ -150,6 +144,7 @@ export const synthesizeTextToSpeech = async ( timeOffset = timeOffset + result.audioDuration } } else { + // assemble ssml const ssml = `${startSsml(null, ssmlOptions)}${input.text}${endSsml()}` await speakSsmlAsyncPromise(ssml) } @@ -159,7 +154,6 @@ export const synthesizeTextToSpeech = async ( } finally { console.debug('closing synthesizer') audioStream.end() - speechMarksStream.end() synthesizer.close() console.debug('synthesizer closed') }