PronounsPage/server/express/pronounce.ts
Valentyne Stigloher b25afefc49 (fmt)
2024-10-29 10:56:32 +01:00

62 lines
2.0 KiB
TypeScript

import { Polly } from '@aws-sdk/client-polly';
import { S3, NoSuchKey } from '@aws-sdk/client-s3';
import type { NodeJsClient } from '@smithy/types';
import { Router } from 'express';
import { Base64 } from 'js-base64';
import sha1 from 'sha1';
import { convertPronunciationStringToSsml, handleErrorAsync } from '../../src/helpers.ts';
import { awsConfig, awsParams } from '../aws.ts';
const router = Router();
router.get('/pronounce/:voice/:pronunciation', handleErrorAsync(async (req, res) => {
const text = Base64.decode(req.params.pronunciation);
if (!text || text.length > 256) {
return res.status(404).json({ error: 'Not found' });
}
const voice = global.config.pronunciation?.voices?.[req.params.voice];
if (!voice) {
return res.status(404).json({ error: 'Not found' });
}
const s3 = new S3(awsConfig) as NodeJsClient<S3>;
const polly = new Polly(awsConfig) as NodeJsClient<Polly>;
const ssml = convertPronunciationStringToSsml(text);
const key = `pronunciation/${global.config.locale}-${req.params.voice}/${sha1(ssml)}.mp3`;
try {
const s3Response = await s3.getObject({ Key: key, ...awsParams });
res.set('content-type', s3Response.ContentType);
return s3Response.Body!.pipe(res);
} catch (error) {
if (!(error instanceof NoSuchKey)) {
throw error;
}
const pollyResponse = await polly.synthesizeSpeech({
TextType: 'ssml',
Text: ssml,
OutputFormat: 'mp3',
LanguageCode: voice.language,
VoiceId: voice.voice,
Engine: voice.engine,
});
const buffer = await pollyResponse.AudioStream!.transformToByteArray();
await s3.putObject({
Key: key,
Body: buffer,
ContentType: pollyResponse.ContentType,
...awsParams,
});
res.set('content-type', pollyResponse.ContentType);
res.write(buffer);
return res.end();
}
}));
export default router;