Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
3.9 kB · 119 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120// Say, 23.09.01.01.11// 23.08.16.14.04 (as TTS)// Generate speech from text using Google TTS, based on parameters.
/* #region 🏁 TODO - [🟡] Try and run in production. + Done - [x] Get the basic function working on vercel. - https://vercel.com/docs/functions/edge-functions/quickstart - [x] Move over the environment variables (remove from netlify) - [x] Get everything working locally.#endregion */
const tts = require("@google-cloud/text-to-speech");const gcpKey = process.env.GCP_TTS_KEY;const gcpEmail = process.env.GCP_EMAIL;
export default async function handler(req, res) { const { method, body } = req;
for (const [k, v] of Object.entries(corsHeaders(req))) res.setHeader(k, v);
if (method === "OPTIONS") { res.status(200).json({ message: "Success!" }); } else if (method === "POST") { const client = new tts.TextToSpeechClient({ credentials: { private_key: gcpKey.replace(/\\n/g, "\n"), client_email: gcpEmail, }, });
const utterance = body.from || "aesthetic.computer"; const set = parseInt(body.voice?.split(":")[1]) || 0; const gender = body.voice?.split(":")[0]?.toUpperCase() || "NEUTRAL"; const voices = ( await client.listVoices({ languageCode: "en-US", }) )[0].voices;
const females = voices .filter((v) => v.ssmlGender === "FEMALE") .sort((a, b) => { return a.name.localeCompare(b.name); });
const males = voices .filter((v) => v.ssmlGender === "MALE") .sort((a, b) => { return a.name.localeCompare(b.name); });
let voice;
if (gender === "MALE") { voice = males[set]; } else if (gender === "FEMALE") { voice = females[set]; } else { voice = males[1]; // Different male. }
const ttsRequest = { voice: { languageCode: "en-US", ...voice }, audioConfig: { audioEncoding: "MP3" }, };
let ssml = false; if (utterance.indexOf("<speak>") !== -1) ssml = true; ttsRequest.input = ssml ? { ssml: utterance } : { text: utterance };
client .synthesizeSpeech(ttsRequest) .then((ttsResponse) => { const audioContent = ttsResponse[0].audioContent; if (!audioContent) { res.status(500).json(ttsResponse); } else { res.setHeader( "Content-Disposition", 'inline; filename="response.mp3"', ); res.setHeader("Content-Type", "audio/mpeg"); // console.log( // "Sending audio content:", // audioContent.length, // utterance, // JSON.stringify(ttsResponse[0]) // ); res.status(200).send(audioContent); } }) .catch((err) => { res.status(500).json({ message: "An error has occurred." }); }); } else { res.status(405).json({ message: "Method Not Allowed" }); }}
// See also: `help.mjs`// TODO: Could not import like in `ask.ts` because of the JS environment.// 23.09.01.19.11// ⚠️ This will not work on other *.ac domains.function corsHeaders(request) { const dev = process.env.VERCEL_ENV === "development"; const production = !dev; let allowedOrigin = production ? "https://aesthetic.computer" : "*"; if (request.headers.origin === "null") allowedOrigin = "*";
return { "Access-Control-Allow-Methods": "GET,OPTIONS,PATCH,DELETE,POST,PUT", "Access-Control-Allow-Origin": allowedOrigin, "Access-Control-Allow-Credentials": true, "Access-Control-Allow-Headers": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version", }; // Define CORS headers.}